Browse Source

Add IDxcSourceLocation::GetPresumedLocation (#2240)

Add IDxcSourceLocation::GetPresumedLocation as a wrapper for clang_getPresumedLocation.

This is important for (e.g.) showing errors in the correct location in IDEs when the #line directive is used, primarily in generated code.
Tim Jones 6 years ago
parent
commit
1ad10b616b

+ 4 - 0
include/dxc/dxcisense.h

@@ -729,6 +729,10 @@ IDxcSourceLocation : public IUnknown
     _Out_opt_ unsigned* pCol,
     _Out_opt_ unsigned* pOffset) = 0;
   virtual HRESULT STDMETHODCALLTYPE IsNull(_Out_ BOOL* pResult) = 0;
+  virtual HRESULT STDMETHODCALLTYPE GetPresumedLocation(
+    _Outptr_opt_ LPSTR* pFilename,
+    _Out_opt_ unsigned* pLine,
+    _Out_opt_ unsigned* pCol) = 0;
 };
 
 struct __declspec(uuid("f1359b36-a53f-4e81-b514-b6b84122a13f"))

+ 20 - 0
tools/clang/tools/libclang/dxcisenseimpl.cpp

@@ -1349,6 +1349,26 @@ HRESULT DxcSourceLocation::IsNull(_Out_ BOOL* pResult)
   return S_OK;
 }
 
+HRESULT DxcSourceLocation::GetPresumedLocation(
+  _Outptr_opt_ LPSTR* pFilename,
+  _Out_opt_ unsigned* pLine,
+  _Out_opt_ unsigned* pCol)
+{
+  DxcThreadMalloc TM(m_pMalloc);
+  
+  CXString filename;
+  unsigned line, col;
+  clang_getPresumedLocation(m_location, &filename, &line, &col);
+  if (pFilename != nullptr)
+  {
+    HRESULT hr = CXStringToAnsiAndDispose(filename, pFilename);
+    if (FAILED(hr)) return hr;
+  }
+  if (pLine) *pLine = line;
+  if (pCol) *pCol = col;
+  return S_OK;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 DxcSourceRange::DxcSourceRange()

+ 4 - 0
tools/clang/tools/libclang/dxcisenseimpl.h

@@ -244,6 +244,10 @@ public:
     _Out_opt_ unsigned* pCol,
     _Out_opt_ unsigned* pOffset) override;
   HRESULT STDMETHODCALLTYPE IsNull(_Out_ BOOL* pResult) override;
+  HRESULT STDMETHODCALLTYPE GetPresumedLocation(
+    _Outptr_opt_ LPSTR* pFilename,
+    _Out_opt_ unsigned* pLine,
+    _Out_opt_ unsigned* pCol) override;
 };
 
 class DxcSourceRange : public IDxcSourceRange

+ 56 - 0
tools/clang/unittests/HLSL/DXIsenseTest.cpp

@@ -85,6 +85,8 @@ protected:
   }
 
   TEST_METHOD(CursorWhenCBufferRefThenFound)
+  TEST_METHOD(CursorWhenPresumedLocationDifferentFromSpellingLocation)
+  TEST_METHOD(CursorWhenPresumedLocationSameAsSpellingLocation)
   TEST_METHOD(CursorWhenFieldRefThenSimpleNames)
   TEST_METHOD(CursorWhenFindAtBodyCallThenMatch)
   TEST_METHOD(CursorWhenFindAtGlobalThenMatch)
@@ -161,6 +163,60 @@ TEST_F(DXIntellisenseTest, CursorWhenCBufferRefThenFound) {
   VERIFY_ARE_EQUAL(2U, line);
 }
 
+TEST_F(DXIntellisenseTest, CursorWhenPresumedLocationDifferentFromSpellingLocation) {
+  char program[] =
+    "#line 21 \"something.h\"\r\n"
+    "struct MyStruct { };";
+
+  CComPtr<IDxcCursor> varCursor;
+  CComPtr<IDxcSourceLocation> loc;
+  CComPtr<IDxcFile> spellingFile;
+  unsigned spellingLine, spellingCol, spellingOffset;
+  CComHeapPtr<char> presumedFilename;
+  unsigned presumedLine, presumedCol;
+  
+  CompilationResult c(CompilationResult::CreateForProgram(program, strlen(program)));
+  VERIFY_ARE_EQUAL(true, c.ParseSucceeded());
+  ExpectCursorAt(c.TU, 2, 1, DxcCursor_StructDecl, &varCursor);
+  VERIFY_SUCCEEDED(varCursor->GetLocation(&loc));
+
+  VERIFY_SUCCEEDED(loc->GetSpellingLocation(&spellingFile, &spellingLine, &spellingCol, &spellingOffset));
+  VERIFY_ARE_EQUAL(2u, spellingLine);
+  VERIFY_ARE_EQUAL(8u, spellingCol);
+  VERIFY_ARE_EQUAL(31u, spellingOffset);
+
+  VERIFY_SUCCEEDED(loc->GetPresumedLocation(&presumedFilename, &presumedLine, &presumedCol));
+  VERIFY_ARE_EQUAL_STR("something.h", presumedFilename);
+  VERIFY_ARE_EQUAL(21u, presumedLine);
+  VERIFY_ARE_EQUAL(8u, presumedCol);
+}
+
+TEST_F(DXIntellisenseTest, CursorWhenPresumedLocationSameAsSpellingLocation) {
+  char program[] = "struct MyStruct { };";
+
+  CComPtr<IDxcCursor> varCursor;
+  CComPtr<IDxcSourceLocation> loc;
+  CComPtr<IDxcFile> spellingFile;
+  unsigned spellingLine, spellingCol, spellingOffset;
+  CComHeapPtr<char> presumedFilename;
+  unsigned presumedLine, presumedCol;
+  
+  CompilationResult c(CompilationResult::CreateForProgram(program, strlen(program)));
+  VERIFY_ARE_EQUAL(true, c.ParseSucceeded());
+  ExpectCursorAt(c.TU, 1, 1, DxcCursor_StructDecl, &varCursor);
+  VERIFY_SUCCEEDED(varCursor->GetLocation(&loc));
+  
+  VERIFY_SUCCEEDED(loc->GetSpellingLocation(&spellingFile, &spellingLine, &spellingCol, &spellingOffset));
+  VERIFY_ARE_EQUAL(1u, spellingLine);
+  VERIFY_ARE_EQUAL(8u, spellingCol);
+  VERIFY_ARE_EQUAL(7u, spellingOffset);
+  
+  VERIFY_SUCCEEDED(loc->GetPresumedLocation(&presumedFilename, &presumedLine, &presumedCol));
+  VERIFY_ARE_EQUAL_STR(CompilationResult::getDefaultFileName(), presumedFilename);
+  VERIFY_ARE_EQUAL(1u, presumedLine);
+  VERIFY_ARE_EQUAL(8u, presumedCol);
+}
+
 TEST_F(DXIntellisenseTest, InclusionWhenMissingThenError) {
   CComPtr<IDxcIntelliSense> isense;
   CComPtr<IDxcIndex> index;