forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			234 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| //  This file defines the PathDiagnostic-related interfaces.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "clang/Analysis/PathDiagnostic.h"
 | |
| #include "clang/AST/Expr.h"
 | |
| #include "clang/AST/Decl.h"
 | |
| #include "clang/AST/DeclObjC.h"
 | |
| #include "clang/AST/StmtCXX.h"
 | |
| #include "llvm/ADT/SmallString.h"
 | |
| #include "llvm/Support/Casting.h"
 | |
| #include <sstream>
 | |
| using namespace clang;
 | |
| using llvm::dyn_cast;
 | |
| using llvm::isa;
 | |
| 
 | |
| bool PathDiagnosticMacroPiece::containsEvent() const {
 | |
|   for (const_iterator I = begin(), E = end(); I!=E; ++I) {
 | |
|     if (isa<PathDiagnosticEventPiece>(*I))
 | |
|       return true;
 | |
|     
 | |
|     if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
 | |
|       if (MP->containsEvent())
 | |
|         return true;
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| static size_t GetNumCharsToLastNonPeriod(const char *s) {
 | |
|   const char *start = s;
 | |
|   const char *lastNonPeriod = 0;  
 | |
| 
 | |
|   for ( ; *s != '\0' ; ++s)
 | |
|     if (*s != '.') lastNonPeriod = s;
 | |
|   
 | |
|   if (!lastNonPeriod)
 | |
|     return 0;
 | |
|   
 | |
|   return (lastNonPeriod - start) + 1;
 | |
| }
 | |
| 
 | |
| static inline size_t GetNumCharsToLastNonPeriod(const std::string &s) {
 | |
|   return s.empty () ? 0 : GetNumCharsToLastNonPeriod(&s[0]);
 | |
| }
 | |
| 
 | |
| PathDiagnosticPiece::PathDiagnosticPiece(const std::string& s,
 | |
|                                          Kind k, DisplayHint hint)
 | |
|   : str(s, 0, GetNumCharsToLastNonPeriod(s)), kind(k), Hint(hint) {}
 | |
| 
 | |
| PathDiagnosticPiece::PathDiagnosticPiece(const char* s, Kind k,
 | |
|                                          DisplayHint hint)
 | |
|   : str(s, GetNumCharsToLastNonPeriod(s)), kind(k), Hint(hint) {}
 | |
| 
 | |
| PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
 | |
|   : kind(k), Hint(hint) {}
 | |
| 
 | |
| PathDiagnosticPiece::~PathDiagnosticPiece() {}
 | |
| PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
 | |
| PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
 | |
| 
 | |
| PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {
 | |
|   for (iterator I = begin(), E = end(); I != E; ++I) delete *I;
 | |
| }
 | |
| 
 | |
| PathDiagnostic::PathDiagnostic() : Size(0) {}
 | |
| 
 | |
| PathDiagnostic::~PathDiagnostic() {
 | |
|   for (iterator I = begin(), E = end(); I != E; ++I) delete &*I;
 | |
| }
 | |
| 
 | |
| void PathDiagnostic::resetPath(bool deletePieces) {
 | |
|   Size = 0;
 | |
| 
 | |
|   if (deletePieces)
 | |
|     for (iterator I=begin(), E=end(); I!=E; ++I)
 | |
|       delete &*I;
 | |
|   
 | |
|   path.clear();
 | |
| }
 | |
| 
 | |
| 
 | |
| PathDiagnostic::PathDiagnostic(const char* bugtype, const char* desc,
 | |
|                                const char* category)
 | |
|   : Size(0),
 | |
|     BugType(bugtype, GetNumCharsToLastNonPeriod(bugtype)),
 | |
|     Desc(desc, GetNumCharsToLastNonPeriod(desc)),
 | |
|     Category(category, GetNumCharsToLastNonPeriod(category)) {}
 | |
| 
 | |
| PathDiagnostic::PathDiagnostic(const std::string& bugtype,
 | |
|                                const std::string& desc, 
 | |
|                                const std::string& category)
 | |
|   : Size(0),
 | |
|     BugType(bugtype, 0, GetNumCharsToLastNonPeriod(bugtype)),
 | |
|     Desc(desc, 0, GetNumCharsToLastNonPeriod(desc)),
 | |
|     Category(category, 0, GetNumCharsToLastNonPeriod(category)) {}
 | |
| 
 | |
| void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
 | |
|                                             const DiagnosticInfo &Info) {
 | |
|   
 | |
|   // Create a PathDiagnostic with a single piece.
 | |
|   
 | |
|   PathDiagnostic* D = new PathDiagnostic();
 | |
|   
 | |
|   const char *LevelStr;
 | |
|   switch (DiagLevel) {
 | |
|   default:
 | |
|   case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
 | |
|   case Diagnostic::Note:    LevelStr = "note: "; break;
 | |
|   case Diagnostic::Warning: LevelStr = "warning: "; break;
 | |
|   case Diagnostic::Error:   LevelStr = "error: "; break;
 | |
|   case Diagnostic::Fatal:   LevelStr = "fatal error: "; break;
 | |
|   }
 | |
| 
 | |
|   llvm::SmallString<100> StrC;
 | |
|   StrC += LevelStr;
 | |
|   Info.FormatDiagnostic(StrC);
 | |
|   
 | |
|   PathDiagnosticPiece *P =
 | |
|     new PathDiagnosticEventPiece(Info.getLocation(),
 | |
|                             std::string(StrC.begin(), StrC.end()));
 | |
|   
 | |
|   for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
 | |
|     P->addRange(Info.getRange(i));
 | |
|   for (unsigned i = 0, e = Info.getNumCodeModificationHints(); i != e; ++i)
 | |
|     P->addCodeModificationHint(Info.getCodeModificationHint(i));
 | |
|   D->push_front(P);
 | |
| 
 | |
|   HandlePathDiagnostic(D);  
 | |
| }
 | |
| 
 | |
| //===----------------------------------------------------------------------===//
 | |
| // PathDiagnosticLocation methods.
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| FullSourceLoc PathDiagnosticLocation::asLocation() const {
 | |
|   assert(isValid());
 | |
|   // Note that we want a 'switch' here so that the compiler can warn us in
 | |
|   // case we add more cases.
 | |
|   switch (K) {
 | |
|     case SingleLocK:
 | |
|     case RangeK:
 | |
|       break;
 | |
|     case StmtK:
 | |
|       return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM));
 | |
|     case DeclK:
 | |
|       return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
 | |
|   }
 | |
|   
 | |
|   return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM));
 | |
| }
 | |
| 
 | |
| PathDiagnosticRange PathDiagnosticLocation::asRange() const {
 | |
|   assert(isValid());
 | |
|   // Note that we want a 'switch' here so that the compiler can warn us in
 | |
|   // case we add more cases.
 | |
|   switch (K) {
 | |
|     case SingleLocK:
 | |
|       return PathDiagnosticRange(R, true);
 | |
|     case RangeK:
 | |
|       break;
 | |
|     case StmtK: {
 | |
|       const Stmt *S = asStmt();
 | |
|       switch (S->getStmtClass()) {
 | |
|         default:
 | |
|           break;
 | |
|           // FIXME: Provide better range information for different
 | |
|           //  terminators.
 | |
|         case Stmt::IfStmtClass:
 | |
|         case Stmt::WhileStmtClass:
 | |
|         case Stmt::DoStmtClass:
 | |
|         case Stmt::ForStmtClass:
 | |
|         case Stmt::ChooseExprClass:
 | |
|         case Stmt::IndirectGotoStmtClass:
 | |
|         case Stmt::SwitchStmtClass:
 | |
|         case Stmt::ConditionalOperatorClass:
 | |
|         case Stmt::ObjCForCollectionStmtClass: {
 | |
|           SourceLocation L = S->getLocStart();
 | |
|           return SourceRange(L, L);
 | |
|         }
 | |
|       }
 | |
|       
 | |
|       return S->getSourceRange();
 | |
|     }
 | |
|     case DeclK:
 | |
|       if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
 | |
|         return MD->getSourceRange();
 | |
|       if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
 | |
|         // FIXME: We would like to always get the function body, even
 | |
|         // when it needs to be de-serialized, but getting the
 | |
|         // ASTContext here requires significant changes.
 | |
|         if (Stmt *Body = FD->getBodyIfAvailable()) {
 | |
|           if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Body))
 | |
|             return CS->getSourceRange();
 | |
|           else
 | |
|             return cast<CXXTryStmt>(Body)->getSourceRange();
 | |
|         }
 | |
|       }
 | |
|       else {
 | |
|         SourceLocation L = D->getLocation();
 | |
|         return PathDiagnosticRange(SourceRange(L, L), true);
 | |
|       }
 | |
|   }
 | |
|   
 | |
|   return R;
 | |
| }
 | |
| 
 | |
| void PathDiagnosticLocation::flatten() {
 | |
|   if (K == StmtK) {
 | |
|     R = asRange();
 | |
|     K = RangeK;
 | |
|     S = 0;
 | |
|     D = 0;
 | |
|   }
 | |
|   else if (K == DeclK) {
 | |
|     SourceLocation L = D->getLocation();
 | |
|     R = SourceRange(L, L);
 | |
|     K = SingleLocK;
 | |
|     S = 0;
 | |
|     D = 0;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 |