[cfe-commits] r39459 - in /cfe/cfe/trunk: Driver/clang.cpp clang.xcodeproj/project.pbxproj

clattner at cs.uiuc.edu clattner at cs.uiuc.edu
Wed Jul 11 09:44:39 PDT 2007


Author: clattner
Date: Wed Jul 11 11:44:39 2007
New Revision: 39459

URL: http://llvm.org/viewvc/llvm-project?rev=39459&view=rev
Log:
Use the new source ranges tracking feature to highlight the important pieces
of a subexpression when emitting a diagnostic.  Consider this example:

struct A { int X; };

void test1(void *P, int C) {
  return ((C*40) + *P) / 42+P;
}

void test2(struct A friendlystruct, int C) {
  return (C     *40) + friendlystruct;
}

void test3(struct A friendlystruct, int C) {
  return friendlystruct + test2(friendlystruct
                               , C);
}


clang now produces this output:

t.c:4:18: error: invalid operands to binary expression ('int' and 'void')
  return ((C*40) + *P) / 42+P;
          ~~~~~~ ^ ~~

This shows the important pieces of a nested (and potentially very complex)
expression.


t.c:8:18: error: invalid operands to binary expression ('int' and 'struct A')
  return (C     *40) + friendlystruct;
         ~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~

This shows that tabs in source files (after the 'C') and multichar tokens
(friendlystruct) are handled correctly.



t.c:12:25: error: invalid operands to binary expression ('struct A' and 'void')
  return friendlystruct + test2(friendlystruct
         ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~

This shows how multiline ranges are printed.  Any part of the range that is
not on the same line as the carat is just ignored.  This also shows that
trailing spaces on the line aren't highlighted.

Modified:
    cfe/cfe/trunk/Driver/clang.cpp
    cfe/cfe/trunk/clang.xcodeproj/project.pbxproj

Modified: cfe/cfe/trunk/Driver/clang.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Driver/clang.cpp?rev=39459&r1=39458&r2=39459&view=diff

==============================================================================
--- cfe/cfe/trunk/Driver/clang.cpp (original)
+++ cfe/cfe/trunk/Driver/clang.cpp Wed Jul 11 11:44:39 2007
@@ -337,14 +337,19 @@
   SourceManager &SourceMgr;
   SourceLocation LastWarningLoc;
   HeaderSearch *TheHeaderSearch;
+  Preprocessor *ThePreprocessor;
 public:
   DiagnosticPrinterSTDERR(SourceManager &sourceMgr)
     : SourceMgr(sourceMgr) {}
   
   void setHeaderSearch(HeaderSearch &HS) { TheHeaderSearch = &HS; }
+  void setPreprocessor(Preprocessor &P) { ThePreprocessor = &P; }
   
   void PrintIncludeStack(SourceLocation Pos);
-
+  void HighlightRange(const SourceRange &R, unsigned LineNo,
+                      std::string &CaratLine, const std::string &SourceLine);
+  unsigned GetTokenLength(SourceLocation Loc);
+    
   virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, SourceLocation Pos,
                                 diag::kind ID, const std::string *Strs,
                                 unsigned NumStrs, SourceRange *Ranges, 
@@ -367,6 +372,81 @@
 }
 
 
+/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s)
+/// any characters in LineNo that intersect the SourceRange.
+void DiagnosticPrinterSTDERR::HighlightRange(const SourceRange &R, 
+                                             unsigned LineNo,
+                                             std::string &CaratLine,
+                                             const std::string &SourceLine) {
+  assert(CaratLine.size() == SourceLine.size() &&
+         "Expect a correspondence between source and carat line!");
+  if (!R.isValid()) return;
+
+  unsigned StartLineNo = SourceMgr.getLineNumber(R.Begin());
+  if (StartLineNo > LineNo) return;  // No intersection.
+  
+  unsigned EndLineNo = SourceMgr.getLineNumber(R.End());
+  if (EndLineNo < LineNo) return;  // No intersection.
+  
+  // Compute the column number of the start.
+  unsigned StartColNo = 0;
+  if (StartLineNo == LineNo) {
+    StartColNo = SourceMgr.getColumnNumber(R.Begin());
+    if (StartColNo) --StartColNo;  // Zero base the col #.
+  }
+
+  // Pick the first non-whitespace column.
+  while (StartColNo < SourceLine.size() &&
+         (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
+    ++StartColNo;
+  
+  // Compute the column number of the end.
+  unsigned EndColNo = CaratLine.size();
+  if (EndLineNo == LineNo) {
+    EndColNo = SourceMgr.getColumnNumber(R.End());
+    if (EndColNo) {
+      --EndColNo;  // Zero base the col #.
+      
+      // Add in the length of the token, so that we cover multi-char tokens.
+      EndColNo += GetTokenLength(R.End());
+    } else {
+      EndColNo = CaratLine.size();
+    }
+  }
+  
+  // Pick the last non-whitespace column.
+  while (EndColNo-1 &&
+         (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
+    --EndColNo;
+  
+  // Fill the range with ~'s.
+  assert(StartColNo <= EndColNo && "Invalid range!");
+  for (unsigned i = StartColNo; i != EndColNo; ++i)
+    CaratLine[i] = '~';
+}
+
+
+/// GetTokenLength - Given the source location of a token, determine its length.
+/// This is a fully general function that uses a lexer to relex the token.
+unsigned DiagnosticPrinterSTDERR::GetTokenLength(SourceLocation Loc) {
+  const char *StrData = SourceMgr.getCharacterData(Loc);
+  
+  // Note, this could be special cased for common tokens like identifiers, ')',
+  // etc to make this faster, if it mattered.
+
+  unsigned FileID = Loc.getFileID();
+  
+  // Create a lexer starting at the beginning of this token.
+  Lexer TheLexer(SourceMgr.getBuffer(FileID), FileID,
+                 *ThePreprocessor,  StrData);
+  
+  LexerToken TheTok;
+  TheLexer.LexRawToken(TheTok);
+
+  return TheTok.getLength();
+}
+
+
 void DiagnosticPrinterSTDERR::HandleDiagnostic(Diagnostic::Level Level, 
                                                SourceLocation Pos,
                                                diag::kind ID,
@@ -456,8 +536,9 @@
     // length as the line of source code.
     std::string CaratLine(LineEnd-LineStart, ' ');
     
-    // FIXME: if (NumRanges) use Ranges to output fancy highlighting
-    // Print out the caret itself.
+    // Highlight all of the characters covered by Ranges with ~ characters.
+    for (unsigned i = 0; i != NumRanges; ++i)
+      HighlightRange(Ranges[i], LineNo, CaratLine, SourceLine);
     
     // Next, insert the carat itself.
     if (ColNo < CaratLine.size())
@@ -481,7 +562,7 @@
       SourceLine.insert(i+1, NumSpaces, ' ');
       
       // Insert spaces or ~'s into CaratLine.
-      CaratLine.insert(i+1, NumSpaces, CaratLine[0] == '~' ? '~' : ' ');
+      CaratLine.insert(i+1, NumSpaces, CaratLine[i] == '~' ? '~' : ' ');
     }
     
     // Finally, remove any blank spaces from the end of CaratLine.
@@ -950,6 +1031,7 @@
 ///
 static void ProcessInputFile(const std::string &InFile, 
                              SourceManager &SourceMgr, Diagnostic &Diags,
+                             DiagnosticPrinterSTDERR &OurDiagnosticClient,
                              HeaderSearch &HeaderInfo, TargetInfo &Target,
                              const LangOptions &LangInfo) {
   FileManager &FileMgr = HeaderInfo.getFileMgr();
@@ -957,6 +1039,8 @@
   // Set up the preprocessor with these options.
   Preprocessor PP(Diags, LangInfo, Target, SourceMgr, HeaderInfo);
   
+  OurDiagnosticClient.setPreprocessor(PP);
+  
   // Install things like __POWERPC__, __GNUC__, etc into the macro table.
   std::vector<char> PrologMacros;
   InitializePredefinedMacros(PP, PrologMacros);
@@ -1108,7 +1192,7 @@
   InitializeIncludePaths(HeaderInfo, FileMgr, Diags, LangInfo);
   
   for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i)
-    ProcessInputFile(InputFilenames[i], SourceMgr, Diags,
+    ProcessInputFile(InputFilenames[i], SourceMgr, Diags, OurDiagnosticClient,
                      HeaderInfo, *Target, LangInfo);
   
   if (NumDiagnostics)

Modified: cfe/cfe/trunk/clang.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/clang.xcodeproj/project.pbxproj?rev=39459&r1=39458&r2=39459&view=diff

==============================================================================
--- cfe/cfe/trunk/clang.xcodeproj/project.pbxproj (original)
+++ cfe/cfe/trunk/clang.xcodeproj/project.pbxproj Wed Jul 11 11:44:39 2007
@@ -94,23 +94,6 @@
 		DED7D9E50A5257F6003AD0FB /* ScratchBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */; };
 /* End PBXBuildFile section */
 
-/* Begin PBXBuildStyle section */
-		84D221650BFB885000DAAD04 /* Development */ = {
-			isa = PBXBuildStyle;
-			buildSettings = {
-				COPY_PHASE_STRIP = NO;
-			};
-			name = Development;
-		};
-		84D221660BFB885000DAAD04 /* Deployment */ = {
-			isa = PBXBuildStyle;
-			buildSettings = {
-				COPY_PHASE_STRIP = YES;
-			};
-			name = Deployment;
-		};
-/* End PBXBuildStyle section */
-
 /* Begin PBXCopyFilesBuildPhase section */
 		8DD76F690486A84900D96B5E /* CopyFiles */ = {
 			isa = PBXCopyFilesBuildPhase;
@@ -171,7 +154,7 @@
 		1A30A9E80B93A4C800201A91 /* ExprCXX.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ExprCXX.h; path = clang/AST/ExprCXX.h; sourceTree = "<group>"; };
 		1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = "<group>"; };
 		1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = "<group>"; };
-		8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "compiled.mach-o.executable"; path = clang; sourceTree = BUILT_PRODUCTS_DIR; };
+		8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; };
 		DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = "<group>"; };
 		DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = "<group>"; };
 		DE06BECA0A854E4B0050E87E /* Scope.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Scope.h; path = clang/Parse/Scope.h; sourceTree = "<group>"; };
@@ -493,12 +476,6 @@
 		08FB7793FE84155DC02AAC07 /* Project object */ = {
 			isa = PBXProject;
 			buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
-			buildSettings = {
-			};
-			buildStyles = (
-				84D221650BFB885000DAAD04 /* Development */,
-				84D221660BFB885000DAAD04 /* Deployment */,
-			);
 			hasScannedForEncodings = 1;
 			mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
 			projectDirPath = "";





More information about the cfe-commits mailing list