diff options
| author | Roman Divacky <rdivacky@FreeBSD.org> | 2009-10-14 18:03:49 +0000 |
|---|---|---|
| committer | Roman Divacky <rdivacky@FreeBSD.org> | 2009-10-14 18:03:49 +0000 |
| commit | 4c8b24812ddcd1dedaca343a6d4e76f91f398981 (patch) | |
| tree | 137ebebcae16fb0ce7ab4af456992bbd8d22fced /utils | |
| parent | 5362a71c02e7d448a8ce98cf00c47e353fba5d04 (diff) | |
Notes
Diffstat (limited to 'utils')
| -rwxr-xr-x | utils/ABITest/ABITestGen.py | 2 | ||||
| -rw-r--r-- | utils/C++Tests/LLVM-Syntax/lit.local.cfg | 22 | ||||
| -rw-r--r-- | utils/C++Tests/lit.cfg | 18 | ||||
| -rw-r--r-- | utils/C++Tests/stdc++-Syntax/lit.local.cfg | 17 | ||||
| -rwxr-xr-x | utils/CaptureCmd | 2 | ||||
| -rwxr-xr-x | utils/CmpDriver | 88 | ||||
| -rwxr-xr-x | utils/FindSpecRefs | 2 | ||||
| -rwxr-xr-x | utils/SummarizeErrors | 2 | ||||
| -rwxr-xr-x | utils/analyzer/CmpRuns | 230 | ||||
| -rwxr-xr-x | utils/ccc-analyzer | 139 | ||||
| -rw-r--r-- | utils/clang-completion-mode.el | 257 | ||||
| -rwxr-xr-x | utils/scan-build | 67 | ||||
| -rw-r--r-- | utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp | 23 |
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_ +} |
