aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2009-10-14 18:03:49 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2009-10-14 18:03:49 +0000
commit4c8b24812ddcd1dedaca343a6d4e76f91f398981 (patch)
tree137ebebcae16fb0ce7ab4af456992bbd8d22fced /utils
parent5362a71c02e7d448a8ce98cf00c47e353fba5d04 (diff)
Notes
Diffstat (limited to 'utils')
-rwxr-xr-xutils/ABITest/ABITestGen.py2
-rw-r--r--utils/C++Tests/LLVM-Syntax/lit.local.cfg22
-rw-r--r--utils/C++Tests/lit.cfg18
-rw-r--r--utils/C++Tests/stdc++-Syntax/lit.local.cfg17
-rwxr-xr-xutils/CaptureCmd2
-rwxr-xr-xutils/CmpDriver88
-rwxr-xr-xutils/FindSpecRefs2
-rwxr-xr-xutils/SummarizeErrors2
-rwxr-xr-xutils/analyzer/CmpRuns230
-rwxr-xr-xutils/ccc-analyzer139
-rw-r--r--utils/clang-completion-mode.el257
-rwxr-xr-xutils/scan-build67
-rw-r--r--utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp23
13 files changed, 736 insertions, 133 deletions
diff --git a/utils/ABITest/ABITestGen.py b/utils/ABITest/ABITestGen.py
index 5598caae3d9b..63da02bcda9d 100755
--- a/utils/ABITest/ABITestGen.py
+++ b/utils/ABITest/ABITestGen.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
from pprint import pprint
import random, atexit, time
diff --git a/utils/C++Tests/LLVM-Syntax/lit.local.cfg b/utils/C++Tests/LLVM-Syntax/lit.local.cfg
new file mode 100644
index 000000000000..69f010ef335e
--- /dev/null
+++ b/utils/C++Tests/LLVM-Syntax/lit.local.cfg
@@ -0,0 +1,22 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+# testFormat: The test format to use to interpret tests.
+config.test_format = lit.formats.SyntaxCheckTest(compiler=root.clang,
+ dir='%s/include/llvm' % root.llvm_src_root,
+ recursive=False,
+ pattern='^(.*\\.h|[^.]*)$',
+ extra_cxx_args=['-D__STDC_LIMIT_MACROS',
+ '-D__STDC_CONSTANT_MACROS',
+ '-I%s/include' % root.llvm_src_root,
+ '-I%s/include' % root.llvm_obj_root])
+
+config.excludes = ['AbstractTypeUser.h']
diff --git a/utils/C++Tests/lit.cfg b/utils/C++Tests/lit.cfg
new file mode 100644
index 000000000000..a7276220209b
--- /dev/null
+++ b/utils/C++Tests/lit.cfg
@@ -0,0 +1,18 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+# Load the main clang test config so we can leech its clang finding logic.
+lit.load_config(config, os.path.join(os.path.dirname(__file__),
+ '..', '..', 'test', 'lit.cfg'))
+assert config.clang, "Failed to set clang!?"
+
+# name: The name of this test suite.
+config.name = 'Clang++'
+
+# suffixes: A list of file extensions to treat as test files, this is actually
+# set by on_clone().
+config.suffixes = []
+
+# Reset these from the Clang config.
+config.test_source_root = config.test_exec_root = None
diff --git a/utils/C++Tests/stdc++-Syntax/lit.local.cfg b/utils/C++Tests/stdc++-Syntax/lit.local.cfg
new file mode 100644
index 000000000000..eb04866e340b
--- /dev/null
+++ b/utils/C++Tests/stdc++-Syntax/lit.local.cfg
@@ -0,0 +1,17 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+# testFormat: The test format to use to interpret tests.
+config.test_format = lit.formats.SyntaxCheckTest(compiler=root.clang,
+ dir='/usr/include/c++/4.2.1',
+ recursive=False,
+ pattern='^(.*\\.h|[^.]*)$')
+
diff --git a/utils/CaptureCmd b/utils/CaptureCmd
index 3bce357e12e8..705585c3bb04 100755
--- a/utils/CaptureCmd
+++ b/utils/CaptureCmd
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
"""CaptureCmd - A generic tool for capturing information about the
invocations of another program.
diff --git a/utils/CmpDriver b/utils/CmpDriver
index 97c91a820915..16b108117d3e 100755
--- a/utils/CmpDriver
+++ b/utils/CmpDriver
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
import subprocess
@@ -33,36 +33,26 @@ def insertMinimumPadding(a, b, dist):
Assumes dist(X, Y) -> int and non-negative.
"""
- # Yay for simplicity over complexity.
+ def cost(a, b):
+ return sum(map(dist, a + [None] * (len(b) - len(a)), b))
- def extend(aElt, bElt, solution):
- d0,(a0,b0) = solution
- return d0 + dist(aElt,bElt), (([aElt]+a0),([bElt]+b0))
+ # Normalize so a is shortest.
+ if len(b) < len(a):
+ b, a = insertMinimumPadding(b, a, dist)
+ return a,b
- def f(a, b):
- if len(a) == len(b):
- return (sum(map(dist, a, b)), (a, b))
-
- if not a or not b:
- if not a:
- a += [None] * len(b)
- else:
- b += [None] * len(a)
- return (sum(map(dist, a, b)), (a, b))
-
- if int(dist(a[0], b[0])) == 0:
- # Non-negative condition implies maximum is satisfied
- # taking this.
- return extend(a[0], b[0], f(a[1:], b[1:]))
-
- if len(a) < len(b):
- return min(f([None] + a, b),
- extend(a[0], b[0], f(a[1:], b[1:])))
- else:
- return min(f(a, [None] + b),
- extend(a[0], b[0], f(a[1:], b[1:])))
-
- return f(a, b)[1]
+ # For each None we have to insert...
+ for i in range(len(b) - len(a)):
+ # For each position we could insert it...
+ current = cost(a, b)
+ best = None
+ for j in range(len(a) + 1):
+ a_0 = a[:j] + [None] + a[j:]
+ candidate = cost(a_0, b)
+ if best is None or candidate < best[0]:
+ best = (candidate, a_0, j)
+ a = best[1]
+ return a,b
class ZipperDiff(object):
"""ZipperDiff - Simple (slow) diff only accomodating inserts."""
@@ -107,7 +97,7 @@ class CompileInfo:
ln.startswith('Configured with: ') or
ln.startswith('Thread model: ') or
ln.startswith('gcc version') or
- ln.startswith('ccc version')):
+ ln.startswith('clang version')):
pass
elif ln.strip().startswith('"'):
self.commands.append(list(splitArgs(ln)))
@@ -131,7 +121,7 @@ def main():
args = sys.argv[1:]
driverA = os.getenv('DRIVER_A') or 'gcc'
- driverB = os.getenv('DRIVER_B') or 'xcc'
+ driverB = os.getenv('DRIVER_B') or 'clang'
infoA = captureDriverInfo(driverA, args)
infoB = captureDriverInfo(driverB, args)
@@ -141,15 +131,41 @@ def main():
# Compare stdout.
if infoA.stdout != infoB.stdout:
print '-- STDOUT DIFFERS -'
- print 'A: ',infoA.stdout
- print 'B: ',infoB.stdout
+ print 'A OUTPUT: ',infoA.stdout
+ print 'B OUTPUT: ',infoB.stdout
+ print
+
+ diff = ZipperDiff(infoA.stdout.split('\n'),
+ infoB.stdout.split('\n'))
+ for i,(aElt,bElt) in enumerate(diff.getDiffs()):
+ if aElt is None:
+ print 'A missing: %s' % bElt
+ elif bElt is None:
+ print 'B missing: %s' % aElt
+ else:
+ print 'mismatch: A: %s' % aElt
+ print ' B: %s' % bElt
+
differ = True
# Compare stderr.
if infoA.stderr != infoB.stderr:
print '-- STDERR DIFFERS -'
- print 'A: ',infoA.stderr
- print 'B: ',infoB.stderr
+ print 'A STDERR: ',infoA.stderr
+ print 'B STDERR: ',infoB.stderr
+ print
+
+ diff = ZipperDiff(infoA.stderr.split('\n'),
+ infoB.stderr.split('\n'))
+ for i,(aElt,bElt) in enumerate(diff.getDiffs()):
+ if aElt is None:
+ print 'A missing: %s' % bElt
+ elif bElt is None:
+ print 'B missing: %s' % aElt
+ else:
+ print 'mismatch: A: %s' % aElt
+ print ' B: %s' % bElt
+
differ = True
# Compare commands.
@@ -191,4 +207,4 @@ def main():
sys.exit(1)
if __name__ == '__main__':
- main()
+ main()
diff --git a/utils/FindSpecRefs b/utils/FindSpecRefs
index c74ca3d22883..9097f93f28d6 100755
--- a/utils/FindSpecRefs
+++ b/utils/FindSpecRefs
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
import os
import re
diff --git a/utils/SummarizeErrors b/utils/SummarizeErrors
index 64d78240dd2f..b6e9122b74cf 100755
--- a/utils/SummarizeErrors
+++ b/utils/SummarizeErrors
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
import os, sys, re
diff --git a/utils/analyzer/CmpRuns b/utils/analyzer/CmpRuns
new file mode 100755
index 000000000000..739d5847734d
--- /dev/null
+++ b/utils/analyzer/CmpRuns
@@ -0,0 +1,230 @@
+#!/usr/bin/env python
+
+"""
+CmpRuns - A simple tool for comparing two static analyzer runs to determine
+which reports have been added, removed, or changed.
+
+This is designed to support automated testing using the static analyzer, from
+two perspectives:
+ 1. To monitor changes in the static analyzer's reports on real code bases, for
+ regression testing.
+
+ 2. For use by end users who want to integrate regular static analyzer testing
+ into a buildbot like environment.
+"""
+
+import os
+import plistlib
+
+#
+
+class multidict:
+ def __init__(self, elts=()):
+ self.data = {}
+ for key,value in elts:
+ self[key] = value
+
+ def __getitem__(self, item):
+ return self.data[item]
+ def __setitem__(self, key, value):
+ if key in self.data:
+ self.data[key].append(value)
+ else:
+ self.data[key] = [value]
+ def items(self):
+ return self.data.items()
+ def values(self):
+ return self.data.values()
+ def keys(self):
+ return self.data.keys()
+ def __len__(self):
+ return len(self.data)
+ def get(self, key, default=None):
+ return self.data.get(key, default)
+
+#
+
+class AnalysisReport:
+ def __init__(self, run, files):
+ self.run = run
+ self.files = files
+
+class AnalysisDiagnostic:
+ def __init__(self, data, report, htmlReport):
+ self.data = data
+ self.report = report
+ self.htmlReport = htmlReport
+
+ def getReadableName(self):
+ loc = self.data['location']
+ filename = self.report.run.getSourceName(self.report.files[loc['file']])
+ line = loc['line']
+ column = loc['col']
+
+ # FIXME: Get a report number based on this key, to 'distinguish'
+ # reports, or something.
+
+ return '%s:%d:%d' % (filename, line, column)
+
+ def getReportData(self):
+ if self.htmlReport is None:
+ return "This diagnostic does not have any report data."
+
+ return open(os.path.join(self.report.run.path,
+ self.htmlReport), "rb").read()
+
+class AnalysisRun:
+ def __init__(self, path, opts):
+ self.path = path
+ self.reports = []
+ self.diagnostics = []
+ self.opts = opts
+
+ def getSourceName(self, path):
+ if path.startswith(self.opts.root):
+ return path[len(self.opts.root):]
+ return path
+
+def loadResults(path, opts):
+ run = AnalysisRun(path, opts)
+
+ for f in os.listdir(path):
+ if (not f.startswith('report') or
+ not f.endswith('plist')):
+ continue
+
+ p = os.path.join(path, f)
+ data = plistlib.readPlist(p)
+
+ # Ignore empty reports.
+ if not data['files']:
+ continue
+
+ # Extract the HTML reports, if they exists.
+ if 'HTMLDiagnostics_files' in data['diagnostics'][0]:
+ htmlFiles = []
+ for d in data['diagnostics']:
+ # FIXME: Why is this named files, when does it have multiple
+ # files?
+ 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'))
+ diagnostics = [AnalysisDiagnostic(d, report, h)
+ for d,h in zip(data.pop('diagnostics'),
+ htmlFiles)]
+
+ assert not data
+
+ run.reports.append(report)
+ run.diagnostics.extend(diagnostics)
+
+ return run
+
+def compareResults(A, B):
+ """
+ compareResults - Generate a relation from diagnostics in run A to
+ diagnostics in run B.
+
+ The result is the relation as a list of triples (a, b, confidence) where
+ each element {a,b} is None or an element from the respective run, and
+ confidence is a measure of the match quality (where 0 indicates equality,
+ and None is used if either element is None).
+ """
+
+ res = []
+
+ # Quickly eliminate equal elements.
+ neqA = []
+ neqB = []
+ eltsA = list(A.diagnostics)
+ eltsB = list(B.diagnostics)
+ eltsA.sort(key = lambda d: d.data)
+ eltsB.sort(key = lambda d: d.data)
+ while eltsA and eltsB:
+ a = eltsA.pop()
+ b = eltsB.pop()
+ if a.data == b.data:
+ res.append((a, b, 0))
+ elif a.data > b.data:
+ neqA.append(a)
+ eltsB.append(b)
+ else:
+ neqB.append(b)
+ eltsA.append(a)
+ neqA.extend(eltsA)
+ neqB.extend(eltsB)
+
+ # FIXME: Add fuzzy matching. One simple and possible effective idea would be
+ # to bin the diagnostics, print them in a normalized form (based solely on
+ # the structure of the diagnostic), compute the diff, then use that as the
+ # basis for matching. This has the nice property that we don't depend in any
+ # way on the diagnostic format.
+
+ for a in neqA:
+ res.append((a, None, None))
+ for b in neqB:
+ res.append((None, b, None))
+
+ return res
+
+def main():
+ from optparse import OptionParser
+ parser = OptionParser("usage: %prog [options] [dir A] [dir B]")
+ parser.add_option("", "--root", dest="root",
+ help="Prefix to ignore on source files",
+ action="store", type=str, default="")
+ parser.add_option("", "--verbose-log", dest="verboseLog",
+ help="Write additional information to LOG [default=None]",
+ action="store", type=str, default=None,
+ metavar="LOG")
+ (opts, args) = parser.parse_args()
+
+ if len(args) != 2:
+ parser.error("invalid number of arguments")
+
+ dirA,dirB = args
+
+ # Load the run results.
+ resultsA = loadResults(dirA, opts)
+ resultsB = loadResults(dirB, opts)
+
+ # Open the verbose log, if given.
+ if opts.verboseLog:
+ auxLog = open(opts.verboseLog, "wb")
+ else:
+ auxLog = None
+
+ diff = compareResults(resultsA, resultsB)
+ for res in diff:
+ a,b,confidence = res
+ if a is None:
+ print "ADDED: %r" % b.getReadableName()
+ if auxLog:
+ print >>auxLog, ("('ADDED', %r, %r)" % (b.getReadableName(),
+ b.getReportData()))
+ elif b is None:
+ print "REMOVED: %r" % a.getReadableName()
+ if auxLog:
+ print >>auxLog, ("('REMOVED', %r, %r)" % (a.getReadableName(),
+ a.getReportData()))
+ elif confidence:
+ print "CHANGED: %r to %r" % (a.getReadableName(),
+ b.getReadableName())
+ if auxLog:
+ print >>auxLog, ("('CHANGED', %r, %r, %r, %r)"
+ % (a.getReadableName(),
+ b.getReadableName(),
+ a.getReportData(),
+ b.getReportData()))
+ else:
+ pass
+
+ print "TOTAL REPORTS: %r" % len(resultsB.diagnostics)
+ if auxLog:
+ print >>auxLog, "('TOTAL', %r)" % len(resultsB.diagnostics)
+
+if __name__ == '__main__':
+ main()
diff --git a/utils/ccc-analyzer b/utils/ccc-analyzer
index e4bf415b163f..ddc5030bc2ef 100755
--- a/utils/ccc-analyzer
+++ b/utils/ccc-analyzer
@@ -22,6 +22,10 @@ use Text::ParseWords;
my $CC = $ENV{'CCC_CC'};
if (!defined $CC) { $CC = "gcc"; }
+
+my $ReportFailures = $ENV{'CCC_REPORT_FAILURES'};
+if (!defined $ReportFailures) { $ReportFailures = 1; }
+
my $CleanupFile;
my $ResultFile;
@@ -61,18 +65,12 @@ sub ProcessClangFailure {
$prefix = "clang_attribute_ignored";
}
- # Generate the preprocessed file with cc (i.e., gcc).
+ # Generate the preprocessed file with Clang.
my ($PPH, $PPFile) = tempfile( $prefix . "_XXXXXX",
SUFFIX => GetPPExt($Lang),
DIR => $Dir);
-
- system $CC, @$Args, "-E", "-o", $PPFile;
+ system $ClangCC, @$Args, "-E", "-o", $PPFile;
close ($PPH);
-
- # Generate the preprocessed file with clang.
- my $PPFile_Clang = $PPFile;
- $PPFile_Clang =~ s/[.](.+)$/.clang.$1/;
- system $ClangCC, @$Args, "-E", "-o", "$PPFile_Clang";
# Create the info file.
open (OUT, ">", "$PPFile.info.txt") or die "Cannot open $PPFile.info.txt\n";
@@ -172,6 +170,17 @@ sub Analyze {
my @PrintArgs;
my $dir;
+
+ if ($RunAnalyzer) {
+ if (defined $ResultFile) {
+ push @CmdArgs,'-o';
+ push @CmdArgs, $ResultFile;
+ }
+ elsif (defined $HtmlDir) {
+ push @CmdArgs,'-o';
+ push @CmdArgs, $HtmlDir;
+ }
+ }
if ($Verbose) {
$dir = getcwd();
@@ -190,17 +199,6 @@ sub Analyze {
print STDERR "#SHELL (cd '$dir' && @PrintArgs)\n";
}
- if ($RunAnalyzer) {
- if (defined $ResultFile) {
- push @CmdArgs,'-o';
- push @CmdArgs, $ResultFile;
- }
- elsif (defined $HtmlDir) {
- push @CmdArgs,'-o';
- push @CmdArgs, $HtmlDir;
- }
- }
-
if (defined $ENV{'CCC_UBI'}) {
push @CmdArgs,"--analyzer-viz-egraph-ubigraph";
}
@@ -231,59 +229,61 @@ sub Analyze {
my $Result = $?;
# Did the command die because of a signal?
- if ($Result & 127 and $Cmd eq $ClangCC and defined $HtmlDir) {
- ProcessClangFailure($ClangCC, $Lang, $file, \@CmdArgsSansAnalyses, $HtmlDir,
- "Crash", $ofile);
- }
- elsif ($Result) {
- if ($IncludeParserRejects && !($file =~/conftest/)) {
- ProcessClangFailure($ClangCC, $Lang, $file, \@CmdArgsSansAnalyses, $HtmlDir,
- $ParserRejects, $ofile);
+ if ($ReportFailures) {
+ if ($Result & 127 and $Cmd eq $ClangCC and defined $HtmlDir) {
+ ProcessClangFailure($ClangCC, $Lang, $file, \@CmdArgsSansAnalyses,
+ $HtmlDir, "Crash", $ofile);
}
- }
- else {
- # Check if there were any unhandled attributes.
- if (open(CHILD, $ofile)) {
- my %attributes_not_handled;
+ elsif ($Result) {
+ if ($IncludeParserRejects && !($file =~/conftest/)) {
+ ProcessClangFailure($ClangCC, $Lang, $file, \@CmdArgsSansAnalyses,
+ $HtmlDir, $ParserRejects, $ofile);
+ }
+ }
+ else {
+ # Check if there were any unhandled attributes.
+ if (open(CHILD, $ofile)) {
+ my %attributes_not_handled;
- # Don't flag warnings about the following attributes that we
- # know are currently not supported by Clang.
- $attributes_not_handled{"cdecl"} = 1;
+ # Don't flag warnings about the following attributes that we
+ # know are currently not supported by Clang.
+ $attributes_not_handled{"cdecl"} = 1;
- my $ppfile;
- while (<CHILD>) {
- next if (! /warning: '([^\']+)' attribute ignored/);
+ my $ppfile;
+ while (<CHILD>) {
+ next if (! /warning: '([^\']+)' attribute ignored/);
- # Have we already spotted this unhandled attribute?
- next if (defined $attributes_not_handled{$1});
- $attributes_not_handled{$1} = 1;
+ # Have we already spotted this unhandled attribute?
+ next if (defined $attributes_not_handled{$1});
+ $attributes_not_handled{$1} = 1;
- # Get the name of the attribute file.
- my $dir = "$HtmlDir/failures";
- my $afile = "$dir/attribute_ignored_$1.txt";
+ # Get the name of the attribute file.
+ my $dir = "$HtmlDir/failures";
+ my $afile = "$dir/attribute_ignored_$1.txt";
- # Only create another preprocessed file if the attribute file
- # doesn't exist yet.
- next if (-e $afile);
+ # Only create another preprocessed file if the attribute file
+ # doesn't exist yet.
+ next if (-e $afile);
- # Add this file to the list of files that contained this attribute.
- # Generate a preprocessed file if we haven't already.
- if (!(defined $ppfile)) {
- $ppfile = ProcessClangFailure($ClangCC, $Lang, $file,
- \@CmdArgsSansAnalyses,
- $HtmlDir, $AttributeIgnored, $ofile);
- }
+ # Add this file to the list of files that contained this attribute.
+ # Generate a preprocessed file if we haven't already.
+ if (!(defined $ppfile)) {
+ $ppfile = ProcessClangFailure($ClangCC, $Lang, $file,
+ \@CmdArgsSansAnalyses,
+ $HtmlDir, $AttributeIgnored, $ofile);
+ }
- mkpath $dir;
- open(AFILE, ">$afile");
- print AFILE "$ppfile\n";
- close(AFILE);
+ mkpath $dir;
+ open(AFILE, ">$afile");
+ print AFILE "$ppfile\n";
+ close(AFILE);
+ }
+ close CHILD;
}
- close CHILD;
}
}
- `rm -f $ofile`;
+ unlink($ofile);
}
##----------------------------------------------------------------------------##
@@ -378,7 +378,7 @@ if (!defined($Analyses)) { $Analyses = '-checker-cfref'; }
# Get the store model.
my $StoreModel = $ENV{'CCC_ANALYZER_STORE_MODEL'};
-if (!defined $StoreModel) { $StoreModel = "basic"; }
+if (!defined $StoreModel) { $StoreModel = "region"; }
# Get the constraints engine.
my $ConstraintsModel = $ENV{'CCC_ANALYZER_CONSTRAINTS_MODEL'};
@@ -410,7 +410,7 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
my ($ArgKey) = split /=/,$Arg,2;
# Modes ccc-analyzer supports
- if ($Arg eq '-E') { $Action = 'preprocess'; }
+ if ($Arg =~ /^-(E|MM?)$/) { $Action = 'preprocess'; }
elsif ($Arg eq '-c') { $Action = 'compile'; }
elsif ($Arg =~ /^-print-prog-name/) { exit 0; }
@@ -539,11 +539,20 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
open(IN, $ARGV[$i+1]);
while (<IN>) { s/\015?\012//; push @Files,$_; }
close(IN);
- ++$i; next;
+ ++$i;
+ next;
}
+ # Handle -Wno-. We don't care about extra warnings, but
+ # we should suppress ones that we don't want to see.
+ if ($Arg =~ /^-Wno-/) {
+ push @CompileOpts, $Arg;
+ next;
+ }
+
if (!($Arg =~ /^-/)) {
- push @Files,$Arg; next;
+ push @Files, $Arg;
+ next;
}
}
@@ -584,7 +593,7 @@ if ($Action eq 'compile' or $Action eq 'link') {
if (defined $OutputFormat) {
push @AnalyzeArgs, "-analyzer-output=" . $OutputFormat;
- if ($OutputFormat eq "plist") {
+ if ($OutputFormat =~ /plist/) {
# Change "Output" to be a file.
my ($h, $f) = tempfile("report-XXXXXX", SUFFIX => ".plist",
DIR => $HtmlDir);
diff --git a/utils/clang-completion-mode.el b/utils/clang-completion-mode.el
new file mode 100644
index 000000000000..690fcda4c454
--- /dev/null
+++ b/utils/clang-completion-mode.el
@@ -0,0 +1,257 @@
+;;; Clang Code-Completion minor mode, for use with C/Objective-C/C++.
+
+;;; Commentary:
+
+;; This minor mode uses Clang's command line interface for code
+;; completion to provide code completion results for C, Objective-C,
+;; and C++ source files. When enabled, Clang will provide
+;; code-completion results in a secondary buffer based on the code
+;; being typed. For example, after typing "struct " (triggered via the
+;; space), Clang will provide the names of all structs visible from
+;; the current scope. After typing "p->" (triggered via the ">"),
+;; Clang will provide the names of all of the members of whatever
+;; class/struct/union "p" points to. Note that this minor mode isn't
+;; meant for serious use: it is meant to help experiment with code
+;; completion based on Clang. It needs your help to make it better!
+;;
+;; To use the Clang code completion mode, first make sure that the
+;; "clang-cc" variable below refers to the "clang-cc" executable,
+;; which is typically installed in libexec/. Then, place
+;; clang-completion-mode.el somewhere in your Emacs load path. You can
+;; add a new load path to Emacs by adding some like the following to
+;; your .emacs:
+;;
+;; (setq load-path (cons "~/.emacs.d" load-path))
+;;
+;; Then, use
+;;
+;; M-x load-library
+;;
+;; to load the library in your Emacs session or add the following to
+;; your .emacs to always load this mode (not recommended):
+;;
+;; (load-library "clang-completion-mode")
+;;
+;; Finally, to try Clang-based code completion in a particular buffer,
+;; use M-x clang-completion-mode. When "Clang-CC" shows up in the mode
+;; line, Clang's code-completion is enabled.
+;;
+;; Clang's code completion is based on parsing the complete source
+;; file up to the point where the cursor is located. Therefore, Clang
+;; needs all of the various compilation flags (include paths, dialect
+;; options, etc.) to provide code-completion results. Currently, these
+;; need to be placed into the clang-cc-flags variable in a format
+;; acceptable to clang-cc. This is a hack: patches are welcome to
+;; improve the interface between this Emacs mode and Clang!
+;;
+
+;;; Code:
+;;; The clang-cc executable
+(defcustom clang-cc "clang-cc"
+ "The location of the clang-cc executable of the Clang compiler.
+This executable is typically installed into the libexec subdirectory."
+ :type 'file
+ :group 'clang-completion-mode)
+
+;;; Extra compilation flags to pass to clang-cc.
+(defcustom clang-cc-flags ""
+ "Extra flags to pass to the Clang executable.
+This variable will typically contain include paths, e.g., -I~/MyProject."
+ :type 'string
+ :group 'clang-completion-mode)
+
+;;; The prefix header to use with Clang code completion.
+(setq clang-completion-prefix-header "")
+
+;;; The substring we will use to filter completion results
+(setq clang-completion-substring "")
+
+;;; The current completion buffer
+(setq clang-completion-buffer nil)
+
+(setq clang-cc-result-string "")
+
+;;; Compute the current line in the buffer
+(defun current-line ()
+ "Return the vertical position of point..."
+ (+ (count-lines (point-min) (point))
+ (if (= (current-column) 0) 1 0)
+ -1))
+
+;;; Set the Clang prefix header
+(defun clang-prefix-header ()
+ (interactive)
+ (setq clang-completion-prefix-header
+ (read-string "Clang prefix header> " "" clang-completion-prefix-header
+ "")))
+
+;; Process "filter" that keeps track of the code-completion results
+;; produced. We store all of the results in a string, then the
+;; sentinel processes the entire string at once.
+(defun clang-completion-stash-filter (proc string)
+ (setq clang-cc-result-string (concat clang-cc-result-string string)))
+
+;; Filter the given list based on a predicate.
+(defun filter (condp lst)
+ (delq nil
+ (mapcar (lambda (x) (and (funcall condp x) x)) lst)))
+
+;; Determine whether
+(defun is-completion-line (line)
+ (or (string-match "OVERLOAD:" line)
+ (string-match (concat "COMPLETION: " clang-completion-substring) line)))
+
+(defun clang-completion-display (buffer)
+ (let* ((all-lines (split-string clang-cc-result-string "\n"))
+ (completion-lines (filter 'is-completion-line all-lines)))
+ (if (consp completion-lines)
+ (progn
+ ;; Erase the process buffer
+ (let ((cur (current-buffer)))
+ (set-buffer buffer)
+ (goto-char (point-min))
+ (erase-buffer)
+ (set-buffer cur))
+
+ ;; Display the process buffer
+ (display-buffer buffer)
+
+ ;; Insert the code-completion string into the process buffer.
+ (with-current-buffer buffer
+ (insert (mapconcat 'identity completion-lines "\n")))
+ ))))
+
+;; Process "sentinal" that, on successful code completion, replaces the
+;; contents of the code-completion buffer with the new code-completion results
+;; and ensures that the buffer is visible.
+(defun clang-completion-sentinel (proc event)
+ (let* ((all-lines (split-string clang-cc-result-string "\n"))
+ (completion-lines (filter 'is-completion-line all-lines)))
+ (if (consp completion-lines)
+ (progn
+ ;; Erase the process buffer
+ (let ((cur (current-buffer)))
+ (set-buffer (process-buffer proc))
+ (goto-char (point-min))
+ (erase-buffer)
+ (set-buffer cur))
+
+ ;; Display the process buffer
+ (display-buffer (process-buffer proc))
+
+ ;; Insert the code-completion string into the process buffer.
+ (with-current-buffer (process-buffer proc)
+ (insert (mapconcat 'identity completion-lines "\n")))
+ ))))
+
+(defun clang-complete ()
+ (let ((ccstring (concat "-code-completion-at="
+ (buffer-file-name)
+ ":"
+ (number-to-string (+ 1 (current-line)))
+ ":"
+ (number-to-string (+ 1 (current-column)))))
+ (cc-buffer-name (concat "*Clang Completion for " (buffer-name) "*")))
+ ;; Start the code-completion process
+ (if (buffer-file-name)
+ (progn
+ ;; If there is already a code-completion process, kill it first.
+ (let ((cc-proc (get-process "Clang Code-Completion")))
+ (if cc-proc
+ (delete-process cc-proc)))
+
+ (setq clang-completion-substring "")
+ (setq clang-cc-result-string "")
+ (setq clang-completion-buffer cc-buffer-name)
+
+ (let ((cc-proc
+ (if (equal clang-completion-prefix-header "")
+ (start-process "Clang Code-Completion" cc-buffer-name
+ clang-cc "-fsyntax-only" ccstring
+ (buffer-file-name))
+ (start-process "Clang Code-Completion" cc-buffer-name
+ clang-cc "-fsyntax-only" ccstring
+ "-include-pch"
+ (concat clang-completion-prefix-header ".pch")
+ (buffer-file-name)))))
+ (set-process-filter cc-proc 'clang-completion-stash-filter)
+ (set-process-sentinel cc-proc 'clang-completion-sentinel)
+ )))))
+
+;; Code-completion when one of the trigger characters is typed into
+;; the buffer, e.g., '(', ',' or '.'.
+(defun clang-complete-self-insert (arg)
+ (interactive "p")
+ (self-insert-command arg)
+ (save-buffer)
+ (clang-complete))
+
+;; When the user has typed a character that requires the filter to be
+;; updated, do so (and update the display of results).
+(defun clang-update-filter ()
+ (setq clang-completion-substring (thing-at-point 'symbol))
+ (if (get-process "Clang Code-Completion")
+ ()
+ (clang-completion-display clang-completion-buffer)
+ ))
+
+;; Invoked when the user types an alphanumeric character or "_" to
+;; update the filter for the currently-active code completion.
+(defun clang-filter-self-insert (arg)
+ (interactive "p")
+ (self-insert-command arg)
+ (clang-update-filter)
+ )
+
+;; Invoked when the user types the backspace key to update the filter
+;; for the currently-active code completion.
+(defun clang-backspace ()
+ (interactive)
+ (delete-backward-char 1)
+ (clang-update-filter))
+
+;; Invoked when the user types the delete key to update the filter
+;; for the currently-active code completion.
+(defun clang-delete ()
+ (interactive)
+ (delete-backward-char 1)
+ (clang-update-filter))
+
+;; Set up the keymap for the Clang minor mode.
+(defvar clang-completion-mode-map nil
+ "Keymap for Clang Completion Mode.")
+
+(if (null clang-completion-mode-map)
+ (fset 'clang-completion-mode-map
+ (setq clang-completion-mode-map (make-sparse-keymap))))
+
+(if (not (assq 'clang-completion-mode minor-mode-map-alist))
+ (setq minor-mode-map-alist
+ (cons (cons 'clang-completion-mode clang-completion-mode-map)
+ minor-mode-map-alist)))
+
+;; Punctuation characters trigger code completion.
+(dolist (char '("(" "," "." ">" ":" "=" ")" " "))
+ (define-key clang-completion-mode-map char 'clang-complete-self-insert))
+
+;; Alphanumeric characters (and "_") filter the results of the
+;; currently-active code completion.
+(dolist (char '("A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O"
+ "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"
+ "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o"
+ "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"
+ "_" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"))
+ (define-key clang-completion-mode-map char 'clang-filter-self-insert))
+
+;; Delete and backspace filter the results of the currently-active
+;; code completion.
+(define-key clang-completion-mode-map [(backspace)] 'clang-backspace)
+(define-key clang-completion-mode-map [(delete)] 'clang-delete)
+
+;; Set up the Clang minor mode.
+(define-minor-mode clang-completion-mode
+ "Clang code-completion mode"
+ nil
+ " Clang-CC"
+ clang-completion-mode-map)
+
diff --git a/utils/scan-build b/utils/scan-build
index 5835628d59ba..78394b179d56 100755
--- a/utils/scan-build
+++ b/utils/scan-build
@@ -148,6 +148,7 @@ my %AnalysesDefaultEnabled = (
# Do not enable the missing -dealloc check by default.
# '-warn-objc-missing-dealloc' => 1,
'-warn-objc-unused-ivars' => 1,
+ '-warn-security-syntactic' => 1
);
##----------------------------------------------------------------------------##
@@ -382,32 +383,25 @@ sub ScanFile {
my $BugCategory;
my $BugPathLength = 1;
my $BugLine = 0;
- my $found = 0;
while (<IN>) {
-
- last if ($found == 5);
+ last if (/<!-- BUGMETAEND -->/);
if (/<!-- BUGTYPE (.*) -->$/) {
$BugType = $1;
- ++$found;
}
elsif (/<!-- BUGFILE (.*) -->$/) {
$BugFile = abs_path($1);
UpdatePrefix($BugFile);
- ++$found;
}
elsif (/<!-- BUGPATHLENGTH (.*) -->$/) {
$BugPathLength = $1;
- ++$found;
}
elsif (/<!-- BUGLINE (.*) -->$/) {
$BugLine = $1;
- ++$found;
}
elsif (/<!-- BUGCATEGORY (.*) -->$/) {
$BugCategory = $1;
- ++$found;
}
}
@@ -955,9 +949,14 @@ ADVANCED OPTIONS:
used by checker-0.160 and earlier.
-store [model] - Specify the store model used by the analyzer. By default,
- the 'basic' store model is used. 'region' specifies a field-
- sensitive store model. Be warned that the 'region' model
- is still in very early testing phase and may often crash.
+ the 'region' store model is used. 'region' specifies a field-
+ sensitive store model. Users can also specify 'basic', which
+ is far less precise but can more quickly analyze code.
+ 'basic' was the default store model for checker-0.221 and
+ earlier.
+
+ -no-failure-reports - Do not create a 'failures' subdirectory that includes
+ analyzer crash reports and preprocessed source files.
AVAILABLE ANALYSES (multiple analyses may be specified):
@@ -1032,7 +1031,7 @@ my $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
my @AnalysesToRun;
my $StoreModel;
my $ConstraintsModel;
-my $OutputFormat;
+my $OutputFormat = "html";
if (!@ARGV) {
DisplayHelp();
@@ -1166,7 +1165,17 @@ while (@ARGV) {
$OutputFormat = "plist";
next;
}
+ if ($arg eq "-plist-html") {
+ shift @ARGV;
+ $OutputFormat = "plist-html";
+ next;
+ }
+ if ($arg eq "-no-failure-reports") {
+ $ENV{"CCC_REPORT_FAILURES"} = 0;
+ next;
+ }
+
DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
last;
@@ -1252,25 +1261,27 @@ if (defined $OutputFormat) {
# Run the build.
my $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd);
-if (defined $OutputFormat and $OutputFormat eq "plist") {
- Diag "Analysis run complete.\n";
- Diag "Analysis results (plist files) deposited in '$HtmlDir'\n";
-}
-else {
- # Postprocess the HTML directory.
- my $NumBugs = Postprocess($HtmlDir, $BaseDir);
-
- if ($ViewResults and -r "$HtmlDir/index.html") {
+if (defined $OutputFormat) {
+ if ($OutputFormat =~ /plist/) {
Diag "Analysis run complete.\n";
- Diag "Viewing analysis results in '$HtmlDir' using scan-view.\n";
- my $ScanView = Cwd::realpath("$RealBin/scan-view");
- if (! -x $ScanView) { $ScanView = "scan-view"; }
- exec $ScanView, "$HtmlDir";
+ Diag "Analysis results (plist files) deposited in '$HtmlDir'\n";
}
+ elsif ($OutputFormat =~ /html/) {
+ # Postprocess the HTML directory.
+ my $NumBugs = Postprocess($HtmlDir, $BaseDir);
- if ($ExitStatusFoundBugs) {
- exit 1 if ($NumBugs > 0);
- exit 0;
+ if ($ViewResults and -r "$HtmlDir/index.html") {
+ Diag "Analysis run complete.\n";
+ Diag "Viewing analysis results in '$HtmlDir' using scan-view.\n";
+ my $ScanView = Cwd::realpath("$RealBin/scan-view");
+ if (! -x $ScanView) { $ScanView = "scan-view"; }
+ exec $ScanView, "$HtmlDir";
+ }
+
+ if ($ExitStatusFoundBugs) {
+ exit 1 if ($NumBugs > 0);
+ exit 0;
+ }
}
}
diff --git a/utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp b/utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp
new file mode 100644
index 000000000000..a86be6cb5dd7
--- /dev/null
+++ b/utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp
@@ -0,0 +1,23 @@
+{
+ libstdcxx_overlapped_memcpy_in_stable_sort_1
+ Memcheck:Overlap
+ fun:memcpy
+ ...
+ fun:_ZSt11stable_sortIN9__gnu_cxx17__normal_iteratorIPSt4pairIPKN4llvm5ValueEjESt6vectorIS7_SaIS7_EEEEN12_GLOBAL__N_116CstSortPredicateEEvT_SF_T0_
+}
+
+{
+ libstdcxx_overlapped_memcpy_in_stable_sort_2
+ Memcheck:Overlap
+ fun:memcpy
+ ...
+ fun:_ZSt11stable_sortIN9__gnu_cxx17__normal_iteratorIPSt4pairIPKN4llvm5ValueEjESt6vectorIS7_SaIS7_EEEEN12_GLOBAL__N_116CstSortPredicateEEvT_SF_T0_
+}
+
+{
+ libstdcxx_overlapped_memcpy_in_stable_sort_3
+ Memcheck:Overlap
+ fun:memcpy
+ ...
+ fun:_ZSt11stable_sortIN9__gnu_cxx17__normal_iteratorIPSt4pairIPKN4llvm4TypeEjESt6vectorIS7_SaIS7_EEEEPFbRKS7_SE_EEvT_SH_T0_
+}