summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/ClangDataFormat.py113
-rw-r--r--utils/TableGen/CMakeLists.txt4
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp4
-rw-r--r--utils/TableGen/ClangCommentCommandInfoEmitter.cpp72
-rw-r--r--utils/TableGen/ClangCommentHTMLTagsEmitter.cpp69
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.cpp20
-rw-r--r--utils/TableGen/ClangSACheckersEmitter.cpp23
-rw-r--r--utils/TableGen/Makefile2
-rw-r--r--utils/TableGen/NeonEmitter.cpp28
-rw-r--r--utils/TableGen/OptParserEmitter.cpp101
-rw-r--r--utils/TableGen/TableGen.cpp175
-rw-r--r--utils/TableGen/TableGenBackends.h5
-rwxr-xr-xutils/analyzer/CmpRuns.py92
-rw-r--r--utils/analyzer/SATestAdd.py18
-rw-r--r--utils/analyzer/SATestBuild.py153
-rw-r--r--utils/analyzer/SumTimerInfo.py17
-rwxr-xr-xutils/analyzer/update_plist_test.pl51
17 files changed, 736 insertions, 211 deletions
diff --git a/utils/ClangDataFormat.py b/utils/ClangDataFormat.py
new file mode 100644
index 000000000000..ec44d2a31b0f
--- /dev/null
+++ b/utils/ClangDataFormat.py
@@ -0,0 +1,113 @@
+"""lldb data formatters for clang classes.
+
+Usage
+--
+import this file in your ~/.lldbinit by adding this line:
+
+command script import /path/to/ClangDataFormat.py
+
+After that, instead of getting this:
+
+(lldb) p Tok.Loc
+(clang::SourceLocation) $0 = {
+ (unsigned int) ID = 123582
+}
+
+you'll get:
+
+(lldb) p Tok.Loc
+(clang::SourceLocation) $4 = "/usr/include/i386/_types.h:37:1" (offset: 123582, file)
+"""
+
+import lldb
+
+def __lldb_init_module(debugger, internal_dict):
+ debugger.HandleCommand("type summary add -F ClangDataFormat.SourceLocation_summary clang::SourceLocation")
+
+def SourceLocation_summary(srcloc, internal_dict):
+ return SourceLocation(srcloc).summary()
+
+class SourceLocation(object):
+ def __init__(self, srcloc):
+ self.srcloc = srcloc
+
+ def offset(self):
+ return getValueFromExpression(self.srcloc, ".getOffset()").GetValueAsUnsigned()
+
+ def isMacro(self):
+ return getValueFromExpression(self.srcloc, ".isMacroID()").GetValueAsUnsigned()
+
+ def getPrint(self, srcmgr_path):
+ print_str = getValueFromExpression(self.srcloc, ".printToString(%s)" % srcmgr_path)
+ return print_str.GetSummary()
+
+ def summary(self):
+ desc = "(offset: %d, %s)" % (self.offset(), "macro" if self.isMacro() else "file")
+ srcmgr_path = findObjectExpressionPath("clang::SourceManager", lldb.frame)
+ if srcmgr_path:
+ desc = self.getPrint(srcmgr_path) + " " + desc
+ return desc
+
+# Key is a (function address, type name) tuple, value is the expression path for
+# an object with such a type name from inside that function.
+FramePathMapCache = {}
+
+def findObjectExpressionPath(typename, frame):
+ func_addr = frame.GetFunction().GetStartAddress().GetFileAddress()
+ key = (func_addr, typename)
+ try:
+ return FramePathMapCache[key]
+ except KeyError:
+ #print "CACHE MISS"
+ path = None
+ obj = findObject(typename, frame)
+ if obj:
+ path = getExpressionPath(obj)
+ FramePathMapCache[key] = path
+ return path
+
+def findObject(typename, frame):
+ def getTypename(value):
+ # FIXME: lldb should provide something like getBaseType
+ ty = value.GetType()
+ if ty.IsPointerType() or ty.IsReferenceType():
+ return ty.GetPointeeType().GetName()
+ return ty.GetName()
+
+ def searchForType(value, searched):
+ tyname = getTypename(value)
+ #print "SEARCH:", getExpressionPath(value), value.GetType().GetName()
+ if tyname == typename:
+ return value
+ ty = value.GetType()
+ if not (ty.IsPointerType() or
+ ty.IsReferenceType() or
+ # FIXME: lldb should provide something like getCanonicalType
+ tyname.startswith("llvm::IntrusiveRefCntPtr<") or
+ tyname.startswith("llvm::OwningPtr<")):
+ return None
+ # FIXME: Hashing for SBTypes does not seem to work correctly, uses the typename instead,
+ # and not the canonical one unfortunately.
+ if tyname in searched:
+ return None
+ searched.add(tyname)
+ for i in range(value.GetNumChildren()):
+ child = value.GetChildAtIndex(i, 0, False)
+ found = searchForType(child, searched)
+ if found:
+ return found
+
+ searched = set()
+ value_list = frame.GetVariables(True, True, True, True)
+ for val in value_list:
+ found = searchForType(val, searched)
+ if found:
+ return found if not found.TypeIsPointerType() else found.Dereference()
+
+def getValueFromExpression(val, expr):
+ return lldb.frame.EvaluateExpression(getExpressionPath(val) + expr)
+
+def getExpressionPath(val):
+ stream = lldb.SBStream()
+ val.GetExpressionPath(stream)
+ return stream.GetData()
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index 0d879214d4a2..534ac9af7760 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -1,10 +1,10 @@
-set(LLVM_REQUIRES_EH 1)
-set(LLVM_REQUIRES_RTTI 1)
set(LLVM_LINK_COMPONENTS Support)
add_tablegen(clang-tblgen CLANG
ClangASTNodesEmitter.cpp
ClangAttrEmitter.cpp
+ ClangCommentCommandInfoEmitter.cpp
+ ClangCommentHTMLTagsEmitter.cpp
ClangDiagnosticsEmitter.cpp
ClangSACheckersEmitter.cpp
NeonEmitter.cpp
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index ef1ad3e1d2d9..521f6046cfa2 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -33,7 +33,7 @@ getValueAsListOfStrings(Record &R, StringRef FieldName) {
i != e;
++i) {
assert(*i && "Got a null element in a ListInit");
- if (StringInit *S = dynamic_cast<StringInit *>(*i))
+ if (StringInit *S = dyn_cast<StringInit>(*i))
Strings.push_back(S->getValue());
else
assert(false && "Got a non-string, non-code element in a ListInit");
@@ -743,8 +743,6 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << " static bool classof(const Attr *A) { return A->getKind() == "
<< "attr::" << R.getName() << "; }\n";
- OS << " static bool classof(const " << R.getName()
- << "Attr *) { return true; }\n";
bool LateParsed = R.getValueAsBit("LateParsed");
OS << " virtual bool isLateParsed() const { return "
diff --git a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
new file mode 100644
index 000000000000..36fbcd40b2f4
--- /dev/null
+++ b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
@@ -0,0 +1,72 @@
+//===--- ClangCommentCommandInfoEmitter.cpp - Generate command lists -----====//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits command lists and efficient matchers command
+// names that are used in documentation comments.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/StringMatcher.h"
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ OS << "namespace {\n"
+ "const CommandInfo Commands[] = {\n";
+ std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Command");
+ for (size_t i = 0, e = Tags.size(); i != e; ++i) {
+ Record &Tag = *Tags[i];
+ OS << " { "
+ << "\"" << Tag.getValueAsString("Name") << "\", "
+ << "\"" << Tag.getValueAsString("EndCommandName") << "\", "
+ << i << ", "
+ << Tag.getValueAsInt("NumArgs") << ", "
+ << Tag.getValueAsBit("IsInlineCommand") << ", "
+ << Tag.getValueAsBit("IsBlockCommand") << ", "
+ << Tag.getValueAsBit("IsBriefCommand") << ", "
+ << Tag.getValueAsBit("IsReturnsCommand") << ", "
+ << Tag.getValueAsBit("IsParamCommand") << ", "
+ << Tag.getValueAsBit("IsTParamCommand") << ", "
+ << Tag.getValueAsBit("IsDeprecatedCommand") << ", "
+ << Tag.getValueAsBit("IsEmptyParagraphAllowed") << ", "
+ << Tag.getValueAsBit("IsVerbatimBlockCommand") << ", "
+ << Tag.getValueAsBit("IsVerbatimBlockEndCommand") << ", "
+ << Tag.getValueAsBit("IsVerbatimLineCommand") << ", "
+ << Tag.getValueAsBit("IsDeclarationCommand") << ", "
+ << /* IsUnknownCommand = */ "0"
+ << " }";
+ if (i + 1 != e)
+ OS << ",";
+ OS << "\n";
+ }
+ OS << "};\n"
+ "} // unnamed namespace\n\n";
+
+ std::vector<StringMatcher::StringPair> Matches;
+ for (size_t i = 0, e = Tags.size(); i != e; ++i) {
+ Record &Tag = *Tags[i];
+ std::string Name = Tag.getValueAsString("Name");
+ std::string Return;
+ raw_string_ostream(Return) << "return &Commands[" << i << "];";
+ Matches.push_back(StringMatcher::StringPair(Name, Return));
+ }
+
+ OS << "const CommandInfo *CommandTraits::getBuiltinCommandInfo(\n"
+ << " StringRef Name) {\n";
+ StringMatcher("Name", Matches, OS).Emit();
+ OS << " return NULL;\n"
+ << "}\n\n";
+}
+} // end namespace clang
+
diff --git a/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp b/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp
new file mode 100644
index 000000000000..0ae23b293e65
--- /dev/null
+++ b/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp
@@ -0,0 +1,69 @@
+//===--- ClangCommentHTMLTagsEmitter.cpp - Generate HTML tag list for Clang -=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits efficient matchers for HTML tags that are used
+// in documentation comments.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/StringMatcher.h"
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+void EmitClangCommentHTMLTags(RecordKeeper &Records, raw_ostream &OS) {
+ std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Tag");
+ std::vector<StringMatcher::StringPair> Matches;
+ for (std::vector<Record *>::iterator I = Tags.begin(), E = Tags.end();
+ I != E; ++I) {
+ Record &Tag = **I;
+ std::string Spelling = Tag.getValueAsString("Spelling");
+ Matches.push_back(StringMatcher::StringPair(Spelling, "return true;"));
+ }
+
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ OS << "bool isHTMLTagName(StringRef Name) {\n";
+ StringMatcher("Name", Matches, OS).Emit();
+ OS << " return false;\n"
+ << "}\n\n";
+}
+
+void EmitClangCommentHTMLTagsProperties(RecordKeeper &Records,
+ raw_ostream &OS) {
+ std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Tag");
+ std::vector<StringMatcher::StringPair> MatchesEndTagOptional;
+ std::vector<StringMatcher::StringPair> MatchesEndTagForbidden;
+ for (std::vector<Record *>::iterator I = Tags.begin(), E = Tags.end();
+ I != E; ++I) {
+ Record &Tag = **I;
+ std::string Spelling = Tag.getValueAsString("Spelling");
+ StringMatcher::StringPair Match(Spelling, "return true;");
+ if (Tag.getValueAsBit("EndTagOptional"))
+ MatchesEndTagOptional.push_back(Match);
+ if (Tag.getValueAsBit("EndTagForbidden"))
+ MatchesEndTagForbidden.push_back(Match);
+ }
+
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ OS << "bool isHTMLEndTagOptional(StringRef Name) {\n";
+ StringMatcher("Name", MatchesEndTagOptional, OS).Emit();
+ OS << " return false;\n"
+ << "}\n\n";
+
+ OS << "bool isHTMLEndTagForbidden(StringRef Name) {\n";
+ StringMatcher("Name", MatchesEndTagForbidden, OS).Emit();
+ OS << " return false;\n"
+ << "}\n\n";
+}
+} // end namespace clang
+
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
index 8615d2db8cda..b1472a87cc10 100644
--- a/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -18,6 +18,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
+#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <algorithm>
@@ -75,7 +76,7 @@ getCategoryFromDiagGroup(const Record *Group,
static std::string getDiagnosticCategory(const Record *R,
DiagGroupParentMap &DiagGroupParents) {
// If the diagnostic is in a group, and that group has a category, use it.
- if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) {
+ if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
// Check the diagnostic's diag group for a category.
std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
DiagGroupParents);
@@ -136,7 +137,7 @@ static void groupDiagnostics(const std::vector<Record*> &Diags,
std::map<std::string, GroupInfo> &DiagsInGroup) {
for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
const Record *R = Diags[i];
- DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"));
+ DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
if (DI == 0) continue;
assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
"Note can't be in a DiagGroup");
@@ -280,7 +281,7 @@ void InferPedantic::compute(VecOrSet DiagsInPedantic,
Record *R = Diags[i];
if (isExtension(R) && isOffByDefault(R)) {
DiagsSet.insert(R);
- if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) {
+ if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
const Record *GroupRec = Group->getDef();
if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
markGroup(GroupRec);
@@ -299,7 +300,7 @@ void InferPedantic::compute(VecOrSet DiagsInPedantic,
// Check if the group is implicitly in -Wpedantic. If so,
// the diagnostic should not be directly included in the -Wpedantic
// diagnostic group.
- if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group")))
+ if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
if (groupInPedantic(Group->getDef()))
continue;
@@ -391,11 +392,11 @@ void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
// Check if this is an error that is accidentally in a warning
// group.
if (isError(R)) {
- if (DefInit *Group = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
+ if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
const Record *GroupRec = Group->getDef();
const std::string &GroupName = GroupRec->getValueAsString("GroupName");
- throw "Error " + R.getName() + " cannot be in a warning group [" +
- GroupName + "]";
+ PrintFatalError(R.getLoc(), "Error " + R.getName() +
+ " cannot be in a warning group [" + GroupName + "]");
}
}
@@ -413,7 +414,7 @@ void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
// Warning associated with the diagnostic. This is stored as an index into
// the alphabetically sorted warning table.
- if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
+ if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
std::map<std::string, GroupInfo>::iterator I =
DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName"));
assert(I != DiagsInGroup.end());
@@ -556,7 +557,8 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789!@#$%^*-+=:?")!=std::string::npos)
- throw "Invalid character in diagnostic group '" + I->first + "'";
+ PrintFatalError("Invalid character in diagnostic group '" +
+ I->first + "'");
OS.write_escaped(I->first) << "\","
<< std::string(MaxLen-I->first.size()+1, ' ');
diff --git a/utils/TableGen/ClangSACheckersEmitter.cpp b/utils/TableGen/ClangSACheckersEmitter.cpp
index 5a0db501dff9..8c74064a6368 100644
--- a/utils/TableGen/ClangSACheckersEmitter.cpp
+++ b/utils/TableGen/ClangSACheckersEmitter.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/DenseSet.h"
+#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <map>
@@ -28,7 +29,7 @@ static bool isHidden(const Record &R) {
if (R.getValueAsBit("Hidden"))
return true;
// Not declared as hidden, check the parent package if it is hidden.
- if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("ParentPackage")))
+ if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("ParentPackage")))
return isHidden(*DI->getDef());
return false;
@@ -42,7 +43,7 @@ static std::string getPackageFullName(const Record *R);
static std::string getParentPackageFullName(const Record *R) {
std::string name;
- if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage")))
+ if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
name = getPackageFullName(DI->getDef());
return name;
}
@@ -63,8 +64,7 @@ static std::string getCheckerFullName(const Record *R) {
}
static std::string getStringValue(const Record &R, StringRef field) {
- if (StringInit *
- SI = dynamic_cast<StringInit*>(R.getValueInit(field)))
+ if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
return SI->getValue();
return std::string();
}
@@ -131,10 +131,11 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
Record *R = checkers[i];
Record *package = 0;
if (DefInit *
- DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage")))
+ DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
package = DI->getDef();
if (!isCheckerNamed(R) && !package)
- throw "Checker '" + R->getName() + "' is neither named, nor in a package!";
+ PrintFatalError(R->getLoc(), "Checker '" + R->getName() +
+ "' is neither named, nor in a package!");
if (isCheckerNamed(R)) {
// Create a pseudo-group to hold this checker.
@@ -151,20 +152,20 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
// Insert the checker and its parent packages into the subgroups set of
// the corresponding parent package.
while (DefInit *DI
- = dynamic_cast<DefInit*>(currR->getValueInit("ParentPackage"))) {
+ = dyn_cast<DefInit>(currR->getValueInit("ParentPackage"))) {
Record *parentPackage = DI->getDef();
recordGroupMap[parentPackage]->SubGroups.insert(currR);
currR = parentPackage;
}
// Insert the checker into the set of its group.
- if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group")))
+ if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")))
recordGroupMap[DI->getDef()]->Checkers.insert(R);
}
// If a package is in group, add all its checkers and its sub-packages
// checkers into the group.
for (unsigned i = 0, e = packages.size(); i != e; ++i)
- if (DefInit *DI = dynamic_cast<DefInit*>(packages[i]->getValueInit("Group")))
+ if (DefInit *DI = dyn_cast<DefInit>(packages[i]->getValueInit("Group")))
addPackageToCheckerGroup(packages[i], DI->getDef(), recordGroupMap);
typedef std::map<std::string, const Record *> SortedRecords;
@@ -205,7 +206,7 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
OS << "PACKAGE(" << "\"";
OS.write_escaped(getPackageFullName(&R)) << "\", ";
// Group index
- if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
+ if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
OS << groupToSortIndex[DI->getDef()] << ", ";
else
OS << "-1, ";
@@ -233,7 +234,7 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
OS << "\"";
OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
// Group index
- if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
+ if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
OS << groupToSortIndex[DI->getDef()] << ", ";
else
OS << "-1, ";
diff --git a/utils/TableGen/Makefile b/utils/TableGen/Makefile
index 9790efc061ef..1fde852ebc47 100644
--- a/utils/TableGen/Makefile
+++ b/utils/TableGen/Makefile
@@ -10,8 +10,6 @@
LEVEL = ../../../..
TOOLNAME = clang-tblgen
USEDLIBS = LLVMTableGen.a LLVMSupport.a
-REQUIRES_EH := 1
-REQUIRES_RTTI := 1
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp
index 68373063baae..d453ededd5e9 100644
--- a/utils/TableGen/NeonEmitter.cpp
+++ b/utils/TableGen/NeonEmitter.cpp
@@ -245,7 +245,7 @@ static void ParseTypes(Record *r, std::string &s,
case 'f':
break;
default:
- throw TGError(r->getLoc(),
+ PrintFatalError(r->getLoc(),
"Unexpected letter: " + std::string(data + len, 1));
}
TV.push_back(StringRef(data, len + 1));
@@ -266,7 +266,8 @@ static char Widen(const char t) {
return 'l';
case 'h':
return 'f';
- default: throw "unhandled type in widen!";
+ default:
+ PrintFatalError("unhandled type in widen!");
}
}
@@ -282,7 +283,8 @@ static char Narrow(const char t) {
return 'i';
case 'f':
return 'h';
- default: throw "unhandled type in narrow!";
+ default:
+ PrintFatalError("unhandled type in narrow!");
}
}
@@ -453,7 +455,7 @@ static std::string TypeString(const char mod, StringRef typestr) {
s += quad ? "x4" : "x2";
break;
default:
- throw "unhandled type!";
+ PrintFatalError("unhandled type!");
}
if (mod == '2')
@@ -635,7 +637,7 @@ static std::string MangleName(const std::string &name, StringRef typestr,
}
break;
default:
- throw "unhandled type!";
+ PrintFatalError("unhandled type!");
}
if (ck == ClassB)
s += "_v";
@@ -773,7 +775,7 @@ static unsigned GetNumElements(StringRef typestr, bool &quad) {
case 'h': nElts = 4; break;
case 'f': nElts = 2; break;
default:
- throw "unhandled type!";
+ PrintFatalError("unhandled type!");
}
if (quad) nElts <<= 1;
return nElts;
@@ -1004,7 +1006,7 @@ static std::string GenOpString(OpKind op, const std::string &proto,
break;
}
default:
- throw "unknown OpKind!";
+ PrintFatalError("unknown OpKind!");
}
return s;
}
@@ -1049,7 +1051,7 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
ET = NeonTypeFlags::Float32;
break;
default:
- throw "unhandled type!";
+ PrintFatalError("unhandled type!");
}
NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g');
return Flags.getFlags();
@@ -1381,7 +1383,7 @@ void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R) {
if (R->getSuperClasses().size() >= 2)
classKind = ClassMap[R->getSuperClasses()[1]];
if (classKind == ClassNone && kind == OpNone)
- throw TGError(R->getLoc(), "Builtin has no class kind");
+ PrintFatalError(R->getLoc(), "Builtin has no class kind");
for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
if (kind == OpReinterpret) {
@@ -1423,7 +1425,7 @@ static unsigned RangeFromType(const char mod, StringRef typestr) {
case 'l':
return (1 << (int)quad) - 1;
default:
- throw "unhandled type!";
+ PrintFatalError("unhandled type!");
}
}
@@ -1456,7 +1458,7 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
ParseTypes(R, Types, TypeVec);
if (R->getSuperClasses().size() < 2)
- throw TGError(R->getLoc(), "Builtin has no class kind");
+ PrintFatalError(R->getLoc(), "Builtin has no class kind");
std::string name = R->getValueAsString("Name");
ClassKind ck = ClassMap[R->getSuperClasses()[1]];
@@ -1501,7 +1503,7 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
ParseTypes(R, Types, TypeVec);
if (R->getSuperClasses().size() < 2)
- throw TGError(R->getLoc(), "Builtin has no class kind");
+ PrintFatalError(R->getLoc(), "Builtin has no class kind");
int si = -1, qi = -1;
uint64_t mask = 0, qmask = 0;
@@ -1600,7 +1602,7 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
ParseTypes(R, Types, TypeVec);
if (R->getSuperClasses().size() < 2)
- throw TGError(R->getLoc(), "Builtin has no class kind");
+ PrintFatalError(R->getLoc(), "Builtin has no class kind");
ClassKind ck = ClassMap[R->getSuperClasses()[1]];
diff --git a/utils/TableGen/OptParserEmitter.cpp b/utils/TableGen/OptParserEmitter.cpp
index b0431a9be16b..674c89af9f99 100644
--- a/utils/TableGen/OptParserEmitter.cpp
+++ b/utils/TableGen/OptParserEmitter.cpp
@@ -7,9 +7,15 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+
+#include <map>
+
using namespace llvm;
static int StrCmpOptionName(const char *A, const char *B) {
@@ -32,8 +38,8 @@ static int StrCmpOptionName(const char *A, const char *B) {
}
static int CompareOptionRecords(const void *Av, const void *Bv) {
- const Record *A = *(Record**) Av;
- const Record *B = *(Record**) Bv;
+ const Record *A = *(const Record*const*) Av;
+ const Record *B = *(const Record*const*) Bv;
// Sentinel options precede all others and are only ordered by precedence.
bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel");
@@ -47,16 +53,38 @@ static int CompareOptionRecords(const void *Av, const void *Bv) {
B->getValueAsString("Name").c_str()))
return Cmp;
+ if (!ASent) {
+ std::vector<std::string> APrefixes = A->getValueAsListOfStrings("Prefixes");
+ std::vector<std::string> BPrefixes = B->getValueAsListOfStrings("Prefixes");
+
+ for (std::vector<std::string>::const_iterator APre = APrefixes.begin(),
+ AEPre = APrefixes.end(),
+ BPre = BPrefixes.begin(),
+ BEPre = BPrefixes.end();
+ APre != AEPre &&
+ BPre != BEPre;
+ ++APre, ++BPre) {
+ if (int Cmp = StrCmpOptionName(APre->c_str(), BPre->c_str()))
+ return Cmp;
+ }
+ }
+
// Then by the kind precedence;
int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence");
int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence");
- assert(APrec != BPrec && "Options are equivalent!");
+ if (APrec == BPrec &&
+ A->getValueAsListOfStrings("Prefixes") ==
+ B->getValueAsListOfStrings("Prefixes")) {
+ PrintError(A->getLoc(), Twine("Option is equivilent to"));
+ PrintError(B->getLoc(), Twine("Other defined here"));
+ PrintFatalError("Equivalent Options found.");
+ }
return APrec < BPrec ? -1 : 1;
}
static const std::string getOptionName(const Record &R) {
// Use the record name unless EnumName is defined.
- if (dynamic_cast<UnsetInit*>(R.getValueInit("EnumName")))
+ if (isa<UnsetInit>(R.getValueInit("EnumName")))
return R.getName();
return R.getValueAsString("EnumName");
@@ -86,6 +114,48 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords);
if (GenDefs) {
+ // Generate prefix groups.
+ typedef SmallVector<SmallString<2>, 2> PrefixKeyT;
+ typedef std::map<PrefixKeyT, std::string> PrefixesT;
+ PrefixesT Prefixes;
+ Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0"));
+ unsigned CurPrefix = 0;
+ for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
+ const Record &R = *Opts[i];
+ std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes");
+ PrefixKeyT prfkey(prf.begin(), prf.end());
+ unsigned NewPrefix = CurPrefix + 1;
+ if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") +
+ Twine(NewPrefix)).str())).second)
+ CurPrefix = NewPrefix;
+ }
+
+ OS << "#ifndef PREFIX\n";
+ OS << "#error \"Define PREFIX prior to including this file!\"\n";
+ OS << "#endif\n\n";
+
+ // Dump prefixes.
+ OS << "/////////\n";
+ OS << "// Prefixes\n\n";
+ OS << "#define COMMA ,\n";
+ for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end();
+ I != E; ++I) {
+ OS << "PREFIX(";
+
+ // Prefix name.
+ OS << I->second;
+
+ // Prefix values.
+ OS << ", {";
+ for (PrefixKeyT::const_iterator PI = I->first.begin(),
+ PE = I->first.end(); PI != PE; ++PI) {
+ OS << "\"" << *PI << "\" COMMA ";
+ }
+ OS << "0})\n";
+ }
+ OS << "#undef COMMA\n";
+ OS << "\n";
+
OS << "#ifndef OPTION\n";
OS << "#error \"Define OPTION prior to including this file!\"\n";
OS << "#endif\n\n";
@@ -98,8 +168,11 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
// Start a single option entry.
OS << "OPTION(";
+ // The option prefix;
+ OS << "0";
+
// The option string.
- OS << '"' << R.getValueAsString("Name") << '"';
+ OS << ", \"" << R.getValueAsString("Name") << '"';
// The option identifier name.
OS << ", "<< getOptionName(R);
@@ -109,7 +182,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
// The containing option group (if any).
OS << ", ";
- if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
+ if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
OS << getOptionName(*DI->getDef());
else
OS << "INVALID";
@@ -118,7 +191,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
OS << ", INVALID, 0, 0";
// The option help text.
- if (!dynamic_cast<UnsetInit*>(R.getValueInit("HelpText"))) {
+ if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
OS << ",\n";
OS << " ";
write_cstring(OS, R.getValueAsString("HelpText"));
@@ -138,6 +211,10 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
// Start a single option entry.
OS << "OPTION(";
+ // The option prefix;
+ std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes");
+ OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", ";
+
// The option string.
write_cstring(OS, R.getValueAsString("Name"));
@@ -149,14 +226,14 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
// The containing option group (if any).
OS << ", ";
- if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
+ if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
OS << getOptionName(*DI->getDef());
else
OS << "INVALID";
// The option alias (if any).
OS << ", ";
- if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Alias")))
+ if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias")))
OS << getOptionName(*DI->getDef());
else
OS << "INVALID";
@@ -170,7 +247,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
for (unsigned i = 0, e = LI->size(); i != e; ++i) {
if (i)
OS << " | ";
- OS << dynamic_cast<DefInit*>(LI->getElement(i))->getDef()->getName();
+ OS << cast<DefInit>(LI->getElement(i))->getDef()->getName();
}
}
@@ -178,7 +255,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
OS << ", " << R.getValueAsInt("NumArgs");
// The option help text.
- if (!dynamic_cast<UnsetInit*>(R.getValueInit("HelpText"))) {
+ if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
OS << ",\n";
OS << " ";
write_cstring(OS, R.getValueAsString("HelpText"));
@@ -187,7 +264,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
// The option meta-variable name.
OS << ", ";
- if (!dynamic_cast<UnsetInit*>(R.getValueInit("MetaVarName")))
+ if (!isa<UnsetInit>(R.getValueInit("MetaVarName")))
write_cstring(OS, R.getValueAsString("MetaVarName"));
else
OS << "0";
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index d3408ed20f4d..41471a484c69 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -19,7 +19,6 @@
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Main.h"
#include "llvm/TableGen/Record.h"
-#include "llvm/TableGen/TableGenAction.h"
using namespace llvm;
using namespace clang;
@@ -42,6 +41,9 @@ enum ActionType {
GenClangDeclNodes,
GenClangStmtNodes,
GenClangSACheckers,
+ GenClangCommentHTMLTags,
+ GenClangCommentHTMLTagsProperties,
+ GenClangCommentCommandInfo,
GenOptParserDefs, GenOptParserImpl,
GenArmNeon,
GenArmNeonSema,
@@ -95,6 +97,18 @@ namespace {
"Generate Clang AST statement nodes"),
clEnumValN(GenClangSACheckers, "gen-clang-sa-checkers",
"Generate Clang Static Analyzer checkers"),
+ clEnumValN(GenClangCommentHTMLTags,
+ "gen-clang-comment-html-tags",
+ "Generate efficient matchers for HTML tag "
+ "names that are used in documentation comments"),
+ clEnumValN(GenClangCommentHTMLTagsProperties,
+ "gen-clang-comment-html-tags-properties",
+ "Generate efficient matchers for HTML tag "
+ "properties"),
+ clEnumValN(GenClangCommentCommandInfo,
+ "gen-clang-comment-command-info",
+ "Generate list of commands that are used in "
+ "documentation comments"),
clEnumValN(GenArmNeon, "gen-arm-neon",
"Generate arm_neon.h for clang"),
clEnumValN(GenArmNeonSema, "gen-arm-neon-sema",
@@ -108,82 +122,88 @@ namespace {
cl::desc("Only use warnings from specified component"),
cl::value_desc("component"), cl::Hidden);
-class ClangTableGenAction : public TableGenAction {
-public:
- bool operator()(raw_ostream &OS, RecordKeeper &Records) {
- switch (Action) {
- case GenClangAttrClasses:
- EmitClangAttrClass(Records, OS);
- break;
- case GenClangAttrImpl:
- EmitClangAttrImpl(Records, OS);
- break;
- case GenClangAttrList:
- EmitClangAttrList(Records, OS);
- break;
- case GenClangAttrPCHRead:
- EmitClangAttrPCHRead(Records, OS);
- break;
- case GenClangAttrPCHWrite:
- EmitClangAttrPCHWrite(Records, OS);
- break;
- case GenClangAttrSpellingList:
- EmitClangAttrSpellingList(Records, OS);
- break;
- case GenClangAttrLateParsedList:
- EmitClangAttrLateParsedList(Records, OS);
- break;
- case GenClangAttrTemplateInstantiate:
- EmitClangAttrTemplateInstantiate(Records, OS);
- break;
- case GenClangAttrParsedAttrList:
- EmitClangAttrParsedAttrList(Records, OS);
- break;
- case GenClangAttrParsedAttrKinds:
- EmitClangAttrParsedAttrKinds(Records, OS);
- break;
- case GenClangDiagsDefs:
- EmitClangDiagsDefs(Records, OS, ClangComponent);
- break;
- case GenClangDiagGroups:
- EmitClangDiagGroups(Records, OS);
- break;
- case GenClangDiagsIndexName:
- EmitClangDiagsIndexName(Records, OS);
- break;
- case GenClangCommentNodes:
- EmitClangASTNodes(Records, OS, "Comment", "");
- break;
- case GenClangDeclNodes:
- EmitClangASTNodes(Records, OS, "Decl", "Decl");
- EmitClangDeclContext(Records, OS);
- break;
- case GenClangStmtNodes:
- EmitClangASTNodes(Records, OS, "Stmt", "");
- break;
- case GenClangSACheckers:
- EmitClangSACheckers(Records, OS);
- break;
- case GenOptParserDefs:
- EmitOptParser(Records, OS, true);
- break;
- case GenOptParserImpl:
- EmitOptParser(Records, OS, false);
- break;
- case GenArmNeon:
- EmitNeon(Records, OS);
- break;
- case GenArmNeonSema:
- EmitNeonSema(Records, OS);
- break;
- case GenArmNeonTest:
- EmitNeonTest(Records, OS);
- break;
- }
-
- return false;
+bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
+ switch (Action) {
+ case GenClangAttrClasses:
+ EmitClangAttrClass(Records, OS);
+ break;
+ case GenClangAttrImpl:
+ EmitClangAttrImpl(Records, OS);
+ break;
+ case GenClangAttrList:
+ EmitClangAttrList(Records, OS);
+ break;
+ case GenClangAttrPCHRead:
+ EmitClangAttrPCHRead(Records, OS);
+ break;
+ case GenClangAttrPCHWrite:
+ EmitClangAttrPCHWrite(Records, OS);
+ break;
+ case GenClangAttrSpellingList:
+ EmitClangAttrSpellingList(Records, OS);
+ break;
+ case GenClangAttrLateParsedList:
+ EmitClangAttrLateParsedList(Records, OS);
+ break;
+ case GenClangAttrTemplateInstantiate:
+ EmitClangAttrTemplateInstantiate(Records, OS);
+ break;
+ case GenClangAttrParsedAttrList:
+ EmitClangAttrParsedAttrList(Records, OS);
+ break;
+ case GenClangAttrParsedAttrKinds:
+ EmitClangAttrParsedAttrKinds(Records, OS);
+ break;
+ case GenClangDiagsDefs:
+ EmitClangDiagsDefs(Records, OS, ClangComponent);
+ break;
+ case GenClangDiagGroups:
+ EmitClangDiagGroups(Records, OS);
+ break;
+ case GenClangDiagsIndexName:
+ EmitClangDiagsIndexName(Records, OS);
+ break;
+ case GenClangCommentNodes:
+ EmitClangASTNodes(Records, OS, "Comment", "");
+ break;
+ case GenClangDeclNodes:
+ EmitClangASTNodes(Records, OS, "Decl", "Decl");
+ EmitClangDeclContext(Records, OS);
+ break;
+ case GenClangStmtNodes:
+ EmitClangASTNodes(Records, OS, "Stmt", "");
+ break;
+ case GenClangSACheckers:
+ EmitClangSACheckers(Records, OS);
+ break;
+ case GenClangCommentHTMLTags:
+ EmitClangCommentHTMLTags(Records, OS);
+ break;
+ case GenClangCommentHTMLTagsProperties:
+ EmitClangCommentHTMLTagsProperties(Records, OS);
+ break;
+ case GenClangCommentCommandInfo:
+ EmitClangCommentCommandInfo(Records, OS);
+ break;
+ case GenOptParserDefs:
+ EmitOptParser(Records, OS, true);
+ break;
+ case GenOptParserImpl:
+ EmitOptParser(Records, OS, false);
+ break;
+ case GenArmNeon:
+ EmitNeon(Records, OS);
+ break;
+ case GenArmNeonSema:
+ EmitNeonSema(Records, OS);
+ break;
+ case GenArmNeonTest:
+ EmitNeonTest(Records, OS);
+ break;
}
-};
+
+ return false;
+}
}
int main(int argc, char **argv) {
@@ -191,6 +211,5 @@ int main(int argc, char **argv) {
PrettyStackTraceProgram X(argc, argv);
cl::ParseCommandLineOptions(argc, argv);
- ClangTableGenAction Action;
- return TableGenMain(argv[0], Action);
+ return TableGenMain(argv[0], &ClangTableGenMain);
}
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
index 779de7c734b0..838fc84dcae3 100644
--- a/utils/TableGen/TableGenBackends.h
+++ b/utils/TableGen/TableGenBackends.h
@@ -47,6 +47,11 @@ void EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS);
void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangCommentHTMLTags(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangCommentHTMLTagsProperties(RecordKeeper &Records, raw_ostream &OS);
+
+void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS);
+
void EmitNeon(RecordKeeper &Records, raw_ostream &OS);
void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS);
void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS);
diff --git a/utils/analyzer/CmpRuns.py b/utils/analyzer/CmpRuns.py
index c8f05cbcf474..3ca9b2bbe7eb 100755
--- a/utils/analyzer/CmpRuns.py
+++ b/utils/analyzer/CmpRuns.py
@@ -17,11 +17,8 @@ Usage:
# Load the results of both runs, to obtain lists of the corresponding
# AnalysisDiagnostic objects.
#
- # root - the name of the root directory, which will be disregarded when
- # determining the source file name
- #
- resultsA = loadResults(dirA, opts, root, deleteEmpty)
- resultsB = loadResults(dirB, opts, root, deleteEmpty)
+ resultsA = loadResultsFromSingleRun(singleRunInfoA, deleteEmpty)
+ resultsB = loadResultsFromSingleRun(singleRunInfoB, deleteEmpty)
# Generate a relation from diagnostics in run A to diagnostics in run B
# to obtain a list of triples (a, b, confidence).
@@ -31,8 +28,18 @@ Usage:
import os
import plistlib
+import CmpRuns
+
+# Information about analysis run:
+# path - the analysis output directory
+# root - the name of the root directory, which will be disregarded when
+# determining the source file name
+class SingleRunInfo:
+ def __init__(self, path, root="", verboseLog=None):
+ self.path = path
+ self.root = root
+ self.verboseLog = verboseLog
-#
class AnalysisDiagnostic:
def __init__(self, data, report, htmlReport):
self._data = data
@@ -41,7 +48,11 @@ class AnalysisDiagnostic:
self._htmlReport = htmlReport
def getFileName(self):
- return self._report.run.getSourceName(self._report.files[self._loc['file']])
+ root = self._report.run.root
+ fileName = self._report.files[self._loc['file']]
+ if fileName.startswith(root) :
+ return fileName[len(root):]
+ return fileName
def getLine(self):
return self._loc['line']
@@ -56,12 +67,12 @@ class AnalysisDiagnostic:
return self._data['description']
def getIssueIdentifier(self) :
- id = ''
+ id = self.getFileName() + "+"
if 'issue_context' in self._data :
- id += self._data['issue_context'] + ":"
+ id += self._data['issue_context'] + "+"
if 'issue_hash' in self._data :
- id += str(self._data['issue_hash']) + ":"
- return id + ":" + self.getFileName()
+ id += str(self._data['issue_hash'])
+ return id
def getReport(self):
if self._htmlReport is None:
@@ -72,6 +83,11 @@ class AnalysisDiagnostic:
return '%s:%d:%d, %s: %s' % (self.getFileName(), self.getLine(),
self.getColumn(), self.getCategory(),
self.getDescription())
+
+ # Note, the data format is not an API and may change from one analyzer
+ # version to another.
+ def getRawData(self):
+ return self._data
class multidict:
def __init__(self, elts=()):
@@ -96,8 +112,6 @@ class multidict:
return len(self.data)
def get(self, key, default=None):
return self.data.get(key, default)
-
-#
class CmpOptions:
def __init__(self, verboseLog=None, rootA="", rootB=""):
@@ -106,29 +120,36 @@ class CmpOptions:
self.verboseLog = verboseLog
class AnalysisReport:
- def __init__(self, run, files):
+ def __init__(self, run, files, clang_vers):
self.run = run
+ self.clang_version = clang_vers
self.files = files
+ self.diagnostics = []
class AnalysisRun:
- def __init__(self, path, root, opts):
- self.path = path
- self.root = root
+ def __init__(self, info):
+ self.path = info.path
+ self.root = info.root
+ self.info = info
self.reports = []
+ # Cumulative list of all diagnostics from all the reports.
self.diagnostics = []
- self.opts = opts
- def getSourceName(self, path):
- if path.startswith(self.root):
- return path[len(self.root):]
- return path
+# Backward compatibility API.
def loadResults(path, opts, root = "", deleteEmpty=True):
- run = AnalysisRun(path, root, opts)
+ return loadResultsFromSingleRun(SingleRunInfo(path, root, opts.verboseLog),
+ deleteEmpty)
+
+# Load results of the analyzes from a given output folder.
+# - info is the SingleRunInfo object
+# - deleteEmpty specifies if the empty plist files should be deleted
+def loadResultsFromSingleRun(info, deleteEmpty=True):
+ path = info.path
+ run = AnalysisRun(info)
for f in os.listdir(path):
- if (not f.startswith('report') or
- not f.endswith('plist')):
+ if (not f.endswith('plist')):
continue
p = os.path.join(path, f)
@@ -146,20 +167,23 @@ def loadResults(path, opts, root = "", deleteEmpty=True):
for d in data['diagnostics']:
# FIXME: Why is this named files, when does it have multiple
# files?
- # TODO: Add the assert back in after we fix the
- # plist-html output.
- # assert len(d['HTMLDiagnostics_files']) == 1
+ assert len(d['HTMLDiagnostics_files']) == 1
htmlFiles.append(d.pop('HTMLDiagnostics_files')[0])
else:
htmlFiles = [None] * len(data['diagnostics'])
-
- report = AnalysisReport(run, data.pop('files'))
+
+ clang_version = ''
+ if 'clang_version' in data:
+ clang_version = data.pop('clang_version')
+
+ report = AnalysisReport(run, data.pop('files'), clang_version)
diagnostics = [AnalysisDiagnostic(d, report, h)
for d,h in zip(data.pop('diagnostics'),
htmlFiles)]
assert not data
-
+
+ report.diagnostics.extend(diagnostics)
run.reports.append(report)
run.diagnostics.extend(diagnostics)
@@ -193,12 +217,12 @@ def compareResults(A, B):
b = eltsB.pop()
if (a.getIssueIdentifier() == b.getIssueIdentifier()) :
res.append((a, b, 0))
- elif a._data > b._data:
- neqA.append(a)
+ elif a.getIssueIdentifier() > b.getIssueIdentifier():
eltsB.append(b)
+ neqA.append(a)
else:
- neqB.append(b)
eltsA.append(a)
+ neqB.append(b)
neqA.extend(eltsA)
neqB.extend(eltsB)
diff --git a/utils/analyzer/SATestAdd.py b/utils/analyzer/SATestAdd.py
index 2d32533f6bb0..64ff4ff65683 100644
--- a/utils/analyzer/SATestAdd.py
+++ b/utils/analyzer/SATestAdd.py
@@ -33,7 +33,7 @@ def isExistingProject(PMapFile, projectID) :
# Params:
# Dir is the directory where the sources are.
# ID is a short string used to identify a project.
-def addNewProject(ID, IsScanBuild) :
+def addNewProject(ID, BuildMode) :
CurDir = os.path.abspath(os.curdir)
Dir = SATestBuild.getProjectDir(ID)
if not os.path.exists(Dir):
@@ -41,7 +41,7 @@ def addNewProject(ID, IsScanBuild) :
sys.exit(-1)
# Build the project.
- SATestBuild.testProject(ID, IsScanBuild, IsReferenceBuild=True, Dir=Dir)
+ SATestBuild.testProject(ID, BuildMode, IsReferenceBuild=True, Dir=Dir)
# Add the project ID to the project map.
ProjectMapPath = os.path.join(CurDir, SATestBuild.ProjectMapFile)
@@ -57,7 +57,7 @@ def addNewProject(ID, IsScanBuild) :
print >> sys.stdout, "Reference output has been regenerated."
else:
PMapWriter = csv.writer(PMapFile)
- PMapWriter.writerow( (ID, int(IsScanBuild)) );
+ PMapWriter.writerow( (ID, int(BuildMode)) );
print "The project map is updated: ", ProjectMapPath
finally:
PMapFile.close()
@@ -69,12 +69,14 @@ if __name__ == '__main__':
if len(sys.argv) < 2:
print >> sys.stderr, 'Usage: ', sys.argv[0],\
'project_ID <mode>' \
- 'mode - 0 for single file project; 1 for scan_build'
+ 'mode - 0 for single file project; ' \
+ '1 for scan_build; ' \
+ '2 for single file c++11 project'
sys.exit(-1)
- IsScanBuild = 1
+ BuildMode = 1
if (len(sys.argv) >= 3):
- IsScanBuild = int(sys.argv[2])
- assert((IsScanBuild == 0) | (IsScanBuild == 1))
+ BuildMode = int(sys.argv[2])
+ assert((BuildMode == 0) | (BuildMode == 1) | (BuildMode == 2))
- addNewProject(sys.argv[1], IsScanBuild)
+ addNewProject(sys.argv[1], BuildMode)
diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py
index fd4bc8a8eeef..94123582225f 100644
--- a/utils/analyzer/SATestBuild.py
+++ b/utils/analyzer/SATestBuild.py
@@ -42,39 +42,66 @@ import os
import csv
import sys
import glob
+import math
import shutil
import time
import plistlib
from subprocess import check_call, CalledProcessError
-# Project map stores info about all the "registered" projects.
-ProjectMapFile = "projectMap.csv"
+#------------------------------------------------------------------------------
+# Helper functions.
+#------------------------------------------------------------------------------
-# Names of the project specific scripts.
-# The script that needs to be executed before the build can start.
-CleanupScript = "cleanup_run_static_analyzer.sh"
-# This is a file containing commands for scan-build.
-BuildScript = "run_static_analyzer.cmd"
+def detectCPUs():
+ """
+ Detects the number of CPUs on a system. Cribbed from pp.
+ """
+ # Linux, Unix and MacOS:
+ if hasattr(os, "sysconf"):
+ if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"):
+ # Linux & Unix:
+ ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
+ if isinstance(ncpus, int) and ncpus > 0:
+ return ncpus
+ else: # OSX:
+ return int(capture(['sysctl', '-n', 'hw.ncpu']))
+ # Windows:
+ if os.environ.has_key("NUMBER_OF_PROCESSORS"):
+ ncpus = int(os.environ["NUMBER_OF_PROCESSORS"])
+ if ncpus > 0:
+ return ncpus
+ return 1 # Default
-# The log file name.
-LogFolderName = "Logs"
-BuildLogName = "run_static_analyzer.log"
-# Summary file - contains the summary of the failures. Ex: This info can be be
-# displayed when buildbot detects a build failure.
-NumOfFailuresInSummary = 10
-FailuresSummaryFileName = "failures.txt"
-# Summary of the result diffs.
-DiffsSummaryFileName = "diffs.txt"
+def which(command, paths = None):
+ """which(command, [paths]) - Look up the given command in the paths string
+ (or the PATH environment variable, if unspecified)."""
-# The scan-build result directory.
-SBOutputDirName = "ScanBuildResults"
-SBOutputDirReferencePrefix = "Ref"
+ if paths is None:
+ paths = os.environ.get('PATH','')
-# The list of checkers used during analyzes.
-# Currently, consists of all the non experimental checkers.
-Checkers="experimental.security.taint,core,deadcode,security,unix,osx"
+ # Check for absolute match first.
+ if os.path.exists(command):
+ return command
-Verbose = 1
+ # Would be nice if Python had a lib function for this.
+ if not paths:
+ paths = os.defpath
+
+ # Get suffixes to search.
+ # On Cygwin, 'PATHEXT' may exist but it should not be used.
+ if os.pathsep == ';':
+ pathext = os.environ.get('PATHEXT', '').split(';')
+ else:
+ pathext = ['']
+
+ # Search the paths...
+ for path in paths.split(os.pathsep):
+ for ext in pathext:
+ p = os.path.join(path, command + ext)
+ if os.path.exists(p):
+ return p
+
+ return None
# Make sure we flush the output after every print statement.
class flushfile(object):
@@ -104,6 +131,52 @@ def getSBOutputDirName(IsReferenceBuild) :
else :
return SBOutputDirName
+#------------------------------------------------------------------------------
+# Configuration setup.
+#------------------------------------------------------------------------------
+
+# Find Clang for static analysis.
+Clang = which("clang", os.environ['PATH'])
+if not Clang:
+ print "Error: cannot find 'clang' in PATH"
+ sys.exit(-1)
+
+# Number of jobs.
+Jobs = math.ceil(detectCPUs() * 0.75)
+
+# Project map stores info about all the "registered" projects.
+ProjectMapFile = "projectMap.csv"
+
+# Names of the project specific scripts.
+# The script that needs to be executed before the build can start.
+CleanupScript = "cleanup_run_static_analyzer.sh"
+# This is a file containing commands for scan-build.
+BuildScript = "run_static_analyzer.cmd"
+
+# The log file name.
+LogFolderName = "Logs"
+BuildLogName = "run_static_analyzer.log"
+# Summary file - contains the summary of the failures. Ex: This info can be be
+# displayed when buildbot detects a build failure.
+NumOfFailuresInSummary = 10
+FailuresSummaryFileName = "failures.txt"
+# Summary of the result diffs.
+DiffsSummaryFileName = "diffs.txt"
+
+# The scan-build result directory.
+SBOutputDirName = "ScanBuildResults"
+SBOutputDirReferencePrefix = "Ref"
+
+# The list of checkers used during analyzes.
+# Currently, consists of all the non experimental checkers.
+Checkers="alpha.unix.SimpleStream,alpha.security.taint,core,deadcode,security,unix,osx"
+
+Verbose = 1
+
+#------------------------------------------------------------------------------
+# Test harness logic.
+#------------------------------------------------------------------------------
+
# Run pre-processing script if any.
def runCleanupScript(Dir, PBuildLogFile):
ScriptPath = os.path.join(Dir, CleanupScript)
@@ -129,13 +202,19 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
BuildScriptPath = os.path.join(Dir, BuildScript)
if not os.path.exists(BuildScriptPath):
print "Error: build script is not defined: %s" % BuildScriptPath
- sys.exit(-1)
- SBOptions = "-plist-html -o " + SBOutputDir + " "
+ sys.exit(-1)
+ SBOptions = "--use-analyzer " + Clang + " "
+ SBOptions += "-plist-html -o " + SBOutputDir + " "
SBOptions += "-enable-checker " + Checkers + " "
try:
SBCommandFile = open(BuildScriptPath, "r")
SBPrefix = "scan-build " + SBOptions + " "
for Command in SBCommandFile:
+ # If using 'make', auto imply a -jX argument
+ # to speed up analysis. xcodebuild will
+ # automatically use the maximum number of cores.
+ if Command.startswith("make "):
+ Command += "-j" + Jobs
SBCommand = SBPrefix + Command
if Verbose == 1:
print " Executing: %s" % (SBCommand,)
@@ -160,17 +239,20 @@ def isValidSingleInputFile(FileName):
(Ext == ".m") | (Ext == "")) :
return True
return False
-
+
# Run analysis on a set of preprocessed files.
-def runAnalyzePreprocessed(Dir, SBOutputDir):
+def runAnalyzePreprocessed(Dir, SBOutputDir, Mode):
if os.path.exists(os.path.join(Dir, BuildScript)):
print "Error: The preprocessed files project should not contain %s" % \
BuildScript
raise Exception()
- CmdPrefix = "clang -cc1 -analyze -analyzer-output=plist -w "
+ CmdPrefix = Clang + " -cc1 -analyze -analyzer-output=plist -w "
CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks "
+ if (Mode == 2) :
+ CmdPrefix += "-std=c++11 "
+
PlistPath = os.path.join(Dir, SBOutputDir, "date")
FailPath = os.path.join(PlistPath, "failures");
os.makedirs(FailPath);
@@ -208,7 +290,7 @@ def runAnalyzePreprocessed(Dir, SBOutputDir):
if Failed == False:
os.remove(LogFile.name);
-def buildProject(Dir, SBOutputDir, IsScanBuild, IsReferenceBuild):
+def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
TBegin = time.time()
BuildLogPath = os.path.join(SBOutputDir, LogFolderName, BuildLogName)
@@ -238,10 +320,10 @@ def buildProject(Dir, SBOutputDir, IsScanBuild, IsReferenceBuild):
try:
runCleanupScript(Dir, PBuildLogFile)
- if IsScanBuild:
+ if (ProjectBuildMode == 1):
runScanBuild(Dir, SBOutputDir, PBuildLogFile)
else:
- runAnalyzePreprocessed(Dir, SBOutputDir)
+ runAnalyzePreprocessed(Dir, SBOutputDir, ProjectBuildMode)
if IsReferenceBuild :
runCleanupScript(Dir, PBuildLogFile)
@@ -395,7 +477,7 @@ def updateSVN(Mode, ProjectsMap):
print "Error: SVN update failed."
sys.exit(-1)
-def testProject(ID, IsScanBuild, IsReferenceBuild=False, Dir=None):
+def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Dir=None):
print " \n\n--- Building project %s" % (ID,)
TBegin = time.time()
@@ -409,7 +491,7 @@ def testProject(ID, IsScanBuild, IsReferenceBuild=False, Dir=None):
RelOutputDir = getSBOutputDirName(IsReferenceBuild)
SBOutputDir = os.path.join(Dir, RelOutputDir)
- buildProject(Dir, SBOutputDir, IsScanBuild, IsReferenceBuild)
+ buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild)
checkBuild(SBOutputDir)
@@ -427,8 +509,9 @@ def testAll(IsReferenceBuild = False, UpdateSVN = False):
if (len(I) != 2) :
print "Error: Rows in the ProjectMapFile should have 3 entries."
raise Exception()
- if (not ((I[1] == "1") | (I[1] == "0"))):
- print "Error: Second entry in the ProjectMapFile should be 0 or 1."
+ if (not ((I[1] == "0") | (I[1] == "1") | (I[1] == "2"))):
+ print "Error: Second entry in the ProjectMapFile should be 0" \
+ " (single file), 1 (project), or 2(single file c++11)."
raise Exception()
# When we are regenerating the reference results, we might need to
diff --git a/utils/analyzer/SumTimerInfo.py b/utils/analyzer/SumTimerInfo.py
index a6731bb8f243..4ef1ceb4cec5 100644
--- a/utils/analyzer/SumTimerInfo.py
+++ b/utils/analyzer/SumTimerInfo.py
@@ -28,6 +28,8 @@ if __name__ == '__main__':
ReachableBlocks = 0
ReachedMaxSteps = 0
NumSteps = 0
+ NumInlinedCallSites = 0
+ NumBifurcatedCallSites = 0
MaxCFGSize = 0
Mode = 1
for line in f:
@@ -39,25 +41,31 @@ if __name__ == '__main__':
Count = Count + 1
if (float(s[6]) > MaxTime) :
MaxTime = float(s[6])
- if ((("warning generated." in line) or ("warnings generated." in line)) and Mode == 1) :
+ if ((("warning generated." in line) or ("warnings generated" in line)) and Mode == 1) :
s = line.split()
Warnings = Warnings + int(s[0])
- if (("The # of functions analysed (as top level)." in line) and (Mode == 1)) :
+ if (("The # of functions analysed (as top level)" in line) and (Mode == 1)) :
s = line.split()
FunctionsAnalyzed = FunctionsAnalyzed + int(s[0])
if (("The % of reachable basic blocks" in line) and (Mode == 1)) :
s = line.split()
ReachableBlocks = ReachableBlocks + int(s[0])
- if (("The # of times we reached the max number of steps." in line) and (Mode == 1)) :
+ if (("The # of times we reached the max number of steps" in line) and (Mode == 1)) :
s = line.split()
ReachedMaxSteps = ReachedMaxSteps + int(s[0])
if (("The maximum number of basic blocks in a function" in line) and (Mode == 1)) :
s = line.split()
if (MaxCFGSize < int(s[0])) :
MaxCFGSize = int(s[0])
- if (("The # of steps executed." in line) and (Mode == 1)) :
+ if (("The # of steps executed" in line) and (Mode == 1)) :
s = line.split()
NumSteps = NumSteps + int(s[0])
+ if (("The # of times we inlined a call" in line) and (Mode == 1)) :
+ s = line.split()
+ NumInlinedCallSites = NumInlinedCallSites + int(s[0])
+ if (("The # of times we split the path due to imprecise dynamic dispatch info" in line) and (Mode == 1)) :
+ s = line.split()
+ NumBifurcatedCallSites = NumBifurcatedCallSites + int(s[0])
if ((") Total" in line) and (Mode == 1)) :
s = line.split()
TotalTime = TotalTime + float(s[6])
@@ -69,6 +77,7 @@ if __name__ == '__main__':
print "Reachable Blocks %d" % (ReachableBlocks)
print "Reached Max Steps %d" % (ReachedMaxSteps)
print "Number of Steps %d" % (NumSteps)
+ print "Number of Inlined calls %d (bifurcated %d)" % (NumInlinedCallSites, NumBifurcatedCallSites)
print "MaxTime %f" % (MaxTime)
print "TotalTime %f" % (TotalTime)
print "Max CFG Size %d" % (MaxCFGSize)
diff --git a/utils/analyzer/update_plist_test.pl b/utils/analyzer/update_plist_test.pl
new file mode 100755
index 000000000000..abb74a57c3c1
--- /dev/null
+++ b/utils/analyzer/update_plist_test.pl
@@ -0,0 +1,51 @@
+#!/usr/bin/perl -w
+use strict;
+require File::Temp;
+use File::Temp ();
+
+die "update_plist_test <test file> <plist file>\n" if ($#ARGV < 1);
+my $testFile = shift @ARGV;
+die "error: cannot read file $testFile\n" if (! -r $testFile);
+my $plistFile = shift @ARGV;
+die "error: cannot read file $plistFile\n" if (! -r $plistFile);
+
+# Create a temp file for the new test.
+my $fh = File::Temp->new();
+my $filename = $fh->filename;
+$fh->unlink_on_destroy(1);
+
+# Copy the existing temp file, skipping the FileCheck comments.
+open (IN, $testFile) or die "cannot open $testFile\n";
+while (<IN>) {
+ next if (/^\/\/ CHECK/);
+ print $fh $_;
+}
+close(IN);
+
+# Copy the plist data, and specially format it.
+open (IN, $plistFile) or die "cannot open $plistFile\n";
+my $firstArray = 1;
+my $first = 1;
+while (<IN>) {
+ # Skip everything not indented.
+ next if (/^[^\s]/);
+ # Skip the first array entry, which is for files.
+ if ($firstArray) {
+ if (/<\/array>/) { $firstArray = 0; }
+ next;
+ }
+ # Format the CHECK lines.
+ if ($first) {
+ print $fh "// CHECK: ";
+ $first = 0;
+ }
+ else {
+ print $fh "// CHECK-NEXT: ";
+ }
+ print $fh $_;
+}
+close (IN);
+close ($fh);
+
+`cp $filename $testFile`;
+print "updated $testFile\n";