Compare commits

..

230 Commits

Author SHA1 Message Date
Tom Stellard
d0d8eb2e54 Merging r345839:
------------------------------------------------------------------------
r345839 | erichkeane | 2018-11-01 08:11:43 -0700 (Thu, 01 Nov 2018) | 6 lines

Multiversioning- Ensure all MV functions are emitted.

Multiverson function versions are always used (by the resolver), so ensure that
they are always emitted.

Change-Id: I5d2e0841fddf0d18918b3fb92ae76814add7ee96
------------------------------------------------------------------------

llvm-svn: 348686
2018-12-08 05:06:53 +00:00
Tom Stellard
0a9b9e6746 Merging r345838:
------------------------------------------------------------------------
r345838 | erichkeane | 2018-11-01 08:11:41 -0700 (Thu, 01 Nov 2018) | 8 lines

CPU-Dispatch- Fix type of a member function, prevent deferrals

The member type creation for a cpu-dispatch function was not correctly
including the 'this' parameter, so ensure that the type is properly
determined. Also, disable defer in the cases of emitting the functoins,
as it can end up resulting in the wrong version being emitted.

Change-Id: I0b8fc5e0b0d1ae1a9d98fd54f35f27f6e5d5d083
------------------------------------------------------------------------

llvm-svn: 348684
2018-12-08 04:54:24 +00:00
Tom Stellard
5a9000ba83 Merging r345826:
------------------------------------------------------------------------
r345826 | erichkeane | 2018-11-01 05:50:37 -0700 (Thu, 01 Nov 2018) | 15 lines

CPU-Dispatch-- Fix conflict between 'generic' and 'pentium'

When a dispatch function was being emitted that had both a generic and a
pentium configuration listed, we would assert.  This is because neither
configuration has any 'features' associated with it so they were both
considered the 'default' version.  'pentium' lacks any features because
we implement it in terms of __builtin_cpu_supports (instead of Intel
proprietary checks), which is unable to decern between the two.

The fix for this is to omit the 'generic' version from the dispatcher if
both are present. This permits existing code to compile, and still will
choose the 'best' version available (since 'pentium' is technically
better than 'generic').

Change-Id: I4b69f3e0344e74cbdbb04497845d5895dd05fda0
------------------------------------------------------------------------

llvm-svn: 348682
2018-12-08 04:42:42 +00:00
Tom Stellard
f98e746cba Merging r342152:
------------------------------------------------------------------------
r342152 | erichkeane | 2018-09-13 09:58:24 -0700 (Thu, 13 Sep 2018) | 6 lines

[NFC]Refactor MultiVersion Resolver Emission to combine types

Previously, both types (plus the future target-clones) of
multiversioning had a separate ResolverOption structure and emission
function.  This patch combines the two, at the expense of a slightly
more expensive sorting function.
------------------------------------------------------------------------

llvm-svn: 348681
2018-12-08 04:29:09 +00:00
Tom Stellard
c5ae766829 Merging r348444:
------------------------------------------------------------------------
r348444 | matze | 2018-12-05 17:40:23 -0800 (Wed, 05 Dec 2018) | 15 lines

AArch64: Fix invalid CCMP emission

The code emitting AND-subtrees used to check whether any of the operands
was an OR in order to figure out if the result needs to be negated.
However the OR could be hidden in further subtrees and not immediately
visible.

Change the code so that canEmitConjunction() determines whether the
result of the generated subtree needs to be negated. Cleanup emission
logic to use this. I also changed the code a bit to make all negation
decisions early before we actually emit the subtrees.

This fixes http://llvm.org/PR39550

Differential Revision: https://reviews.llvm.org/D54137
------------------------------------------------------------------------

llvm-svn: 348642
2018-12-07 20:42:27 +00:00
Tom Stellard
fe1944239c Merging r346203:
------------------------------------------------------------------------
r346203 | matze | 2018-11-05 19:15:22 -0800 (Mon, 05 Nov 2018) | 7 lines

AArch64: Cleanup CCMP code; NFC

Cleanup CCMP pattern matching code in preparation for review/bugfix:
- Rename `isConjunctionDisjunctionTree()` to `canEmitConjunction()`
  (it won't accept arbitrary disjunctions and is really about whether we
   can transform the subtree into a conjunction that we can emit).
- Rename `emitConjunctionDisjunctionTree()` to `emitConjunction()`
------------------------------------------------------------------------

llvm-svn: 348636
2018-12-07 20:21:24 +00:00
Tom Stellard
e725fba53c Merging r340125:
------------------------------------------------------------------------
r340125 | lhames | 2018-08-18 11:38:37 -0700 (Sat, 18 Aug 2018) | 6 lines

[RuntimeDyld] Fix a bug in RuntimeDyld::loadObjectImpl that was over-allocating
space for common symbols.

Patch by Dmitry Sidorov. Thanks Dmitry!

Differential revision: https://reviews.llvm.org/D50240
------------------------------------------------------------------------

llvm-svn: 348555
2018-12-07 00:24:01 +00:00
Tom Stellard
c4c4115791 Merging r340386 and r344190:
------------------------------------------------------------------------
r340386 | inouehrs | 2018-08-21 22:43:27 -0700 (Tue, 21 Aug 2018) | 10 lines

[AST] correct the behavior of -fvisibility-inlines-hidden option (don't make static local variables hidden)

The command line option -fvisibility-inlines-hidden makes inlined method hidden, but it is expected not to affect the visibility of static local variables in the function.
However, Clang makes the static local variables in the function also hidden as reported in PR37595. This problem causes LLVM bootstarp failure on Fedora 28 if configured with -DBUILD_SHARED_LIBS=ON.

This patch makes the behavior of -fvisibility-inlines-hidden option to be consistent with that of gcc; the option does not change the visibility of the static local variables if the containing function does not associated with explicit visibility attribute and becomes hidden due to this option.

Differential Revision: https://reviews.llvm.org/D50968

------------------------------------------------------------------------

------------------------------------------------------------------------
r344190 | rnk | 2018-10-10 14:59:56 -0700 (Wed, 10 Oct 2018) | 19 lines

[AST] Use -fvisibility value when ignoring -fv-i-h* inline static locals

Summary:
In r340386 we added code to give static locals in inline functions
default visibility. Instead, we should use the "default" visibility
passed on the command line, which could be hidden or protected, as GCC
does.

Some code bases use both -fvisibility=hidden and
-fvisibility-inlines-hidden to hide inline functions of classes that are
explicitly marked with default visibility.

Fixes PR39236

Reviewers: hans, thakis

Subscribers: eraman, llvm-commits

Differential Revision: https://reviews.llvm.org/D53052
------------------------------------------------------------------------

llvm-svn: 348554
2018-12-07 00:14:58 +00:00
Tom Stellard
b7096f761a Merging r348462:
------------------------------------------------------------------------
r348462 | lebedevri | 2018-12-06 00:14:24 -0800 (Thu, 06 Dec 2018) | 13 lines

[InstCombine] foldICmpWithLowBitMaskedVal(): don't miscompile -1 vector elts

I was finally able to quantify what i thought was missing in the fix,
it was vector constants. If we have a scalar (and %x, -1),
it will be instsimplified before we reach this code,
but if it is a vector, we may still have a -1 element.

Thus, we want to avoid the fold if *at least one* element is -1.
Or in other words, ignoring the undef elements, no sign bits
should be set. Thus, m_NonNegative().

A follow-up for rL348181
https://bugs.llvm.org/show_bug.cgi?id=39861
------------------------------------------------------------------------

llvm-svn: 348538
2018-12-06 22:36:26 +00:00
Tom Stellard
9e856fabe0 Merging r348461:
------------------------------------------------------------------------
r348461 | lebedevri | 2018-12-06 00:11:20 -0800 (Thu, 06 Dec 2018) | 4 lines

[NFC][InstCombine] Add more miscompile tests for foldICmpWithLowBitMaskedVal()

We also have to me aware of vector constants. If at least one element
is -1, we can't transform.
------------------------------------------------------------------------

llvm-svn: 348535
2018-12-06 22:20:44 +00:00
Tom Stellard
2ea572a8e5 Merging r348181:
------------------------------------------------------------------------
r348181 | lebedevri | 2018-12-03 12:07:58 -0800 (Mon, 03 Dec 2018) | 8 lines

[InstCombine] foldICmpWithLowBitMaskedVal(): disable 2 faulty folds.

These two folds are invalid for this non-constant pattern
when the mask ends up being all-ones:
https://rise4fun.com/Alive/9au
https://rise4fun.com/Alive/UcQM

Fixes https://bugs.llvm.org/show_bug.cgi?id=39861
------------------------------------------------------------------------

llvm-svn: 348528
2018-12-06 21:36:42 +00:00
Tom Stellard
a0f6a34313 Merging r343369:
------------------------------------------------------------------------
r343369 | vitalybuka | 2018-09-28 19:17:12 -0700 (Fri, 28 Sep 2018) | 1 line

[cxx2a] Fix warning triggered by r343285
------------------------------------------------------------------------

llvm-svn: 348453
2018-12-06 03:14:54 +00:00
Tom Stellard
e2bdf494cd Merging r343369:
------------------------------------------------------------------------
r343369 | vitalybuka | 2018-09-28 19:17:12 -0700 (Fri, 28 Sep 2018) | 1 line

[cxx2a] Fix warning triggered by r343285
------------------------------------------------------------------------

llvm-svn: 348452
2018-12-06 03:14:46 +00:00
Tom Stellard
5d1a670b7c Merging r343369:
------------------------------------------------------------------------
r343369 | vitalybuka | 2018-09-28 19:17:12 -0700 (Fri, 28 Sep 2018) | 1 line

[cxx2a] Fix warning triggered by r343285
------------------------------------------------------------------------

llvm-svn: 348451
2018-12-06 03:14:33 +00:00
Tom Stellard
9bd05390b3 Merging r343369:
------------------------------------------------------------------------
r343369 | vitalybuka | 2018-09-28 19:17:12 -0700 (Fri, 28 Sep 2018) | 1 line

[cxx2a] Fix warning triggered by r343285
------------------------------------------------------------------------

llvm-svn: 348450
2018-12-06 03:14:29 +00:00
Tom Stellard
b1c89d22f9 Merging r345470:
------------------------------------------------------------------------
r345470 | brad | 2018-10-27 20:30:18 -0700 (Sat, 27 Oct 2018) | 2 lines

Reapply Pass the nopie flag to the linker when linking with -pg.

------------------------------------------------------------------------

llvm-svn: 348405
2018-12-05 19:48:58 +00:00
Adam Balogh
d363502dcd [Analyzer] [HOTFIX!] SValBuilder crash when aggressive-binary-operation-simplification enabled
During the review of D41938 a condition check with an early exit accidentally
slipped into a branch, leaving the other branch unprotected. This may result in
an assertion later on. This hotfix moves this contition check outside of the
branch.

Differential Revision: https://reviews.llvm.org/D55051

llvm-svn: 348362
2018-12-05 13:17:50 +00:00
Tom Stellard
1d3cb9452f Merging r343753:
------------------------------------------------------------------------
r343753 | phosek | 2018-10-03 22:38:53 -0700 (Wed, 03 Oct 2018) | 7 lines

[CMake] Use just basename when copying C++ ABI headers

This avoids duplicate directories when the filename includes path.

Fixes PR39145

Differential Revision: https://reviews.llvm.org/D52762
------------------------------------------------------------------------

llvm-svn: 348322
2018-12-05 00:16:11 +00:00
Tom Stellard
5b036d9701 Merging r344100:
------------------------------------------------------------------------
r344100 | emaste | 2018-10-09 17:34:17 -0700 (Tue, 09 Oct 2018) | 16 lines

clang: Allow ifunc resolvers to accept arguments

When ifunc support was added to Clang (r265917) it did not allow
resolvers to take function arguments.  This was based on GCC's
documentation, which states resolvers return a pointer and take no
arguments.

However, GCC actually allows resolvers to take arguments, and glibc (on
non-x86 platforms) and FreeBSD (on x86 and arm64) pass some CPU
identification information as arguments to ifunc resolvers.  I believe
GCC's documentation is simply incorrect / out-of-date.

FreeBSD already removed the prohibition in their in-tree Clang copy.

Differential Revision:	https://reviews.llvm.org/D52703

------------------------------------------------------------------------

llvm-svn: 348012
2018-11-30 18:15:48 +00:00
Tom Stellard
4d730d8ff3 Merging r344589:
------------------------------------------------------------------------
r344589 | dstenb | 2018-10-16 01:06:48 -0700 (Tue, 16 Oct 2018) | 41 lines

[DebugInfo][LCSSA] Rewrite pre-existing debug values outside loop

Summary:
Extend LCSSA so that debug values outside loops are rewritten to
use the PHI nodes that the pass creates.

This fixes PR39019. In that case, we ran LCSSA on a loop that
was later on vectorized, which left us with something like this:

  for.cond.cleanup:
    %add.lcssa = phi i32 [ %add, %for.body ], [ %34, %middle.block ]
    call void @llvm.dbg.value(metadata i32 %add,
    ret i32 %add.lcssa

  for.body:
    %add =
    [...]
    br i1 %exitcond, label %for.cond.cleanup, label %for.body

which later resulted in the debug.value becoming undef when
removing the scalar loop (and the location would have probably
been wrong for the vectorized case otherwise).

As we now may need to query the AvailableVals cache more than
once for a basic block, FindAvailableVals() in SSAUpdaterImpl is
changed so that it updates the cache for blocks that we do not
create a PHI node for, regardless of the block's number of
predecessors. The debug value in the attached IR reproducer
would not be properly rewritten without this.

Debug values residing in blocks where we have not inserted any
PHI nodes are currently left as-is by this patch. I'm not sure
what should be done with those uses.

Reviewers: mattd, aprantl, vsk, probinson

Reviewed By: mattd, aprantl

Subscribers: jmorse, gbedwell, JDevlieghere, llvm-commits

Differential Revision: https://reviews.llvm.org/D53130
------------------------------------------------------------------------

llvm-svn: 348011
2018-11-30 17:55:00 +00:00
Tom Stellard
4a6ae60f26 Merging r339260:
------------------------------------------------------------------------
r339260 | syzaara | 2018-08-08 08:20:43 -0700 (Wed, 08 Aug 2018) | 13 lines

[PowerPC] Improve codegen for vector loads using scalar_to_vector

This patch aims to improve the codegen for vector loads involving the
scalar_to_vector (load X) sequence. Initially, ld->mv instructions were used
for scalar_to_vector (load X), so this patch allows scalar_to_vector (load X)
to utilize:

LXSD and LXSDX for i64 and f64
LXSIWAX for i32 (sign extension to i64)
LXSIWZX for i32 and f64

Committing on behalf of Amy Kwan.
Differential Revision: https://reviews.llvm.org/D48950
------------------------------------------------------------------------

llvm-svn: 347957
2018-11-30 04:51:41 +00:00
Tom Stellard
d6ffc0c6ea Merging r347556:
------------------------------------------------------------------------
r347556 | nemanjai | 2018-11-26 06:35:38 -0800 (Mon, 26 Nov 2018) | 11 lines

[PowerPC] Vector load/store builtins overstate alignment of pointers

A number of builtins in altivec.h load/store vectors from pointers to scalar
types. Currently they just cast the pointer to a vector pointer, but expressions
like that have the alignment of the target type. Of course, the input pointer
did not have that alignment so this triggers UBSan (and rightly so).

This resolves https://bugs.llvm.org/show_bug.cgi?id=39704

Differential revision: https://reviews.llvm.org/D54787

------------------------------------------------------------------------

llvm-svn: 347935
2018-11-30 00:08:50 +00:00
Tom Stellard
958b37efa2 Merging r347431:
------------------------------------------------------------------------
r347431 | rnk | 2018-11-21 14:01:10 -0800 (Wed, 21 Nov 2018) | 12 lines

[mingw] Use unmangled name after the $ in the section name

GCC does it this way, and we have to be consistent. This includes
stdcall and fastcall functions with suffixes. I confirmed that a
fastcall function named "foo" ends up in ".text$foo", not
".text$@foo@8".

Based on a patch by Andrew Yohn!

Fixes PR39218.

Differential Revision: https://reviews.llvm.org/D54762
------------------------------------------------------------------------

llvm-svn: 347931
2018-11-29 23:40:59 +00:00
Tom Stellard
938be89e4e Merging r344444 and r344445:
------------------------------------------------------------------------
r344444 | baloghadamsoftware | 2018-10-13 03:34:52 -0700 (Sat, 13 Oct 2018) | 11 lines

[clang-tidy] Optimize query in bugprone-exception-escape

Checking whether a functions throws indirectly may be very expensive because it
needs to visit its whole call graph. Therefore we should first check whether the
function is forbidden to throw and only check whether it throws afterward. This
also seems to solve bug https://bugs.llvm.org/show_bug.cgi?id=39167 where the
execution time is so long that it seems to hang.

Differential Revision: https://reviews.llvm.org/D53187

------------------------------------------------------------------------

------------------------------------------------------------------------
r344445 | baloghadamsoftware | 2018-10-13 04:17:59 -0700 (Sat, 13 Oct 2018) | 3 lines

[clang-tidy] Fix for typos in the tests for `bugprone-exception-escape`

------------------------------------------------------------------------

llvm-svn: 347921
2018-11-29 21:27:29 +00:00
Tom Stellard
3ccd033c4e Merging r345497:
------------------------------------------------------------------------
r345497 | asavonic | 2018-10-29 04:14:01 -0700 (Mon, 29 Oct 2018) | 29 lines

[OpenCL] Fix serialization of OpenCLExtensionDecls

Summary:
I recently discovered that adding the following code into `opencl-c.h` causes
failure of `test/Headers/opencl-c-header.cl`:
```
#pragma OPENCL EXTENSION cl_my_ext : begin
void cl_my_ext_foobarbaz();
#pragma OPENCL EXTENSIOn cl_my_ext : end
```

Clang crashes at the assertion is `ASTReader::getGlobalSubmoduleID()`:
```
assert(I != M.SubmoduleRemap.end() && "Invalid index into submodule index remap");
```

The root cause of the problem that to deserialize `OPENCL_EXTENSION_DECLS`
section `ASTReader` needs to deserialize a Decl contained in it. In turn,
deserializing a Decl requires information about whether this declaration is
part of a (sub)module, but this information is not read yet because it is
located further in a module file.

Reviewers: Anastasia, yaxunl, JDevlieghere

Reviewed By: Anastasia

Subscribers: sidorovd, cfe-commits, asavonic

Differential Revision: https://reviews.llvm.org/D53200
------------------------------------------------------------------------

llvm-svn: 347834
2018-11-29 04:37:25 +00:00
Tom Stellard
3e4d4dd038 Merging r343105:
------------------------------------------------------------------------
r343105 | lebedevri | 2018-09-26 06:08:44 -0700 (Wed, 26 Sep 2018) | 17 lines

[analyzer] scan-build: if --status-bugs is passed, don't forget about the exit status of the actual build

Summary:
This has been bothering me for a while, but only now i have actually looked into this.
I'm using one CI job for static analysis - clang static analyzers as compilers + clang-tidy via cmake.
And i'd like for the build to fail if at least one of those finds issues.
If clang-tidy finds issues, it will fail the build since the warnings-as-errors is set.
If static analyzer finds anything, since --status-bugs is set, it will fail the build.
But if clang-tidy find anything, but static analyzer does not, the build succeeds :/

Reviewers: sylvestre.ledru, alexfh, jroelofs, ygribov, george.karpenkov, krememek

Reviewed By: jroelofs

Subscribers: xazax.hun, szepet, a.sidorin, mikhail.ramalho, Szelethus, cfe-commits

Differential Revision: https://reviews.llvm.org/D52530
------------------------------------------------------------------------

llvm-svn: 347829
2018-11-29 02:54:32 +00:00
Tom Stellard
1ee9092683 Merging r347179:
------------------------------------------------------------------------
r347179 | brad | 2018-11-18 16:21:06 -0800 (Sun, 18 Nov 2018) | 4 lines

[PowerPC] Set the default PLT mode on OpenBSD/powerpc to Secure PLT.

OpenBSD/powerpc only supports Secure PLT.

------------------------------------------------------------------------

llvm-svn: 347822
2018-11-29 00:31:15 +00:00
Tom Stellard
9ad6d0609a Merging r342865:
------------------------------------------------------------------------
r342865 | courbet | 2018-09-24 01:39:48 -0700 (Mon, 24 Sep 2018) | 11 lines

[llvm-exegesis] Fix PR39021.

Summary:
The `set` statements was incorrectly reading the value of the local variable and
setting the value of the parent variable.

Reviewers: tycho, gchatelet, john.brawn

Subscribers: mgorny, tschuett, llvm-commits

Differential Revision: https://reviews.llvm.org/D52343
------------------------------------------------------------------------

llvm-svn: 347811
2018-11-28 21:46:14 +00:00
Tom Stellard
f79f472aa1 Merging r347262:
------------------------------------------------------------------------
r347262 | vedantk | 2018-11-19 12:10:22 -0800 (Mon, 19 Nov 2018) | 8 lines

[Coverage] Fix PR39258: support coverage regions that start deeper than they end

popRegions used to assume that the start location of a region can't be
nested deeper than the end location, which is not always true.

Patch by Orivej Desh!

Differential Revision: https://reviews.llvm.org/D53244
------------------------------------------------------------------------

llvm-svn: 347798
2018-11-28 20:04:13 +00:00
Tom Stellard
b948f5fe98 Merging r347261:
------------------------------------------------------------------------
r347261 | vedantk | 2018-11-19 12:10:21 -0800 (Mon, 19 Nov 2018) | 11 lines

[Sema] Fix PR38987: keep end location of a direct initializer list

If PerformConstructorInitialization of a direct initializer list constructor is
called while instantiating a template, it has brace locations in its BraceLoc
arguments but not in the Kind argument.

This reverts the hunk https://reviews.llvm.org/D41921#inline-468844.

Patch by Orivej Desh!

Differential Revision: https://reviews.llvm.org/D53231
------------------------------------------------------------------------

llvm-svn: 347797
2018-11-28 19:50:01 +00:00
Tom Stellard
e4023f8c63 Merging r345353:
------------------------------------------------------------------------
r345353 | sima | 2018-10-25 18:28:36 -0700 (Thu, 25 Oct 2018) | 21 lines

Teach the DominatorTree fallback to recalculation when applying updates to speedup JT (PR37929)

Summary:
This patch makes the dominatortree recalculate when applying updates with the size of the update vector larger than a threshold. Directly applying updates is usually slower than recalculating the whole domtree in this case. This patch fixes an issue which causes JT running slowly on some inputs.

In bug 37929, the dominator tree is trying to apply 19,000+ updates several times, which takes several minutes.

After this patch, the time used by DT.applyUpdates:

| Input | Before (s) | After (s) | Speedup |
| the 2nd Reproducer in 37929 | 297 | 0.15 | 1980x |
| clang-5.0.0.0.bc | 9.7 | 4.3 | 2.26x |
| clang-5.0.0.4.bc | 11.6 | 2.6 | 4.46x |

Reviewers: kuhar, brzycki, trentxintong, davide, dmgreen, grosser

Reviewed By: kuhar, brzycki

Subscribers: kristina, llvm-commits

Differential Revision: https://reviews.llvm.org/D53245
------------------------------------------------------------------------

llvm-svn: 347285
2018-11-20 03:42:43 +00:00
Tom Stellard
e3cd69e00b Merging r341697:
------------------------------------------------------------------------
r341697 | arphaman | 2018-09-07 11:59:45 -0700 (Fri, 07 Sep 2018) | 4 lines

warn_stdlibcxx_not_found: suggest '-stdlib=libc++' instead of '-std'

Addresses first post-commit feedback for r335081 from Nico

------------------------------------------------------------------------

llvm-svn: 347276
2018-11-20 00:36:24 +00:00
Tom Stellard
85e1cc5cd7 Merging r344605:
------------------------------------------------------------------------
r344605 | jankratochvil | 2018-10-16 04:38:22 -0700 (Tue, 16 Oct 2018) | 12 lines

Fix: Assertion failed: (!m_first_die || m_first_die == m_die_array.front()), function ExtractDIEsRWLocked

xbolva00 bugreported $subj in: https://reviews.llvm.org/D46810#1247410
It can happen only from the line:
	m_die_array.back().SetEmptyChildren(true);

In the case DW_TAG_compile_unit has DW_CHILDREN_yes but there is only 0 (end of
list, no children present). Therefore the assertion can fortunately happen only
with a hand-crafted DWARF or with DWARF from some suboptimal compilers.

Differential Revision: https://reviews.llvm.org/D53255

------------------------------------------------------------------------

llvm-svn: 347030
2018-11-16 06:04:28 +00:00
Tom Stellard
35aa48a4a4 Merging r344591:
------------------------------------------------------------------------
r344591 | abeserminji | 2018-10-16 01:27:28 -0700 (Tue, 16 Oct 2018) | 11 lines

[mips][micromips] Fix how values in .gcc_except_table are calculated

When a landing pad is calculated in a program that is compiled
for micromips, it will point to an even address. Such an error will
cause a segmentation fault, as the instructions in micromips are
aligned on odd addresses. This patch sets the last bit of the offset
where a landing pad is, to 1, which will effectively be
an odd address and point to the instruction exactly.

Differential Revision: https://reviews.llvm.org/D52985

------------------------------------------------------------------------

llvm-svn: 347028
2018-11-16 05:16:44 +00:00
Tom Stellard
77480c54e9 Merging r343212:
------------------------------------------------------------------------
r343212 | meinersbur | 2018-09-27 06:39:37 -0700 (Thu, 27 Sep 2018) | 37 lines

[IslAst] Fix InParallelFor nesting.

IslAst could mark two nested outer loops as "OutermostParallel". It
caused that the code generator tried to OpenMP-parallelize both loops,
which it is not prepared loop.

It was because the recursive AST build algorithm managed a flag
"InParallelFor" to ensure that no nested loop is also marked as
"OutermostParallel". Unfortunatetly the same flag was used by nodes
marked as SIMD, and reset to false after the SIMD node. Since loops can
be marked as SIMD inside "OutermostParallel" loops, the recursive
algorithm again tried to mark loops as "OutermostParellel" although
still nested inside another "OutermostParallel" loop.

The fix exposed another bug: The function "astScheduleDimIsParallel" was
only called when a loop was potentially "OutermostParallel" or
"InnermostParallel", but as a side-effect also determines the minimum
dependence distance. Hence, changing when we need to know whether a loop
is "OutermostParallel" also changed which loop was annotated with
"#pragma minimal dependence distance".

Moreover, some complex condition linked with "InParallelFor" determined
whether a loop should be an "InnermostParallel" loop. It missed some
situations where it would not use mark as such although being inside an
SIMD mark node, and therefore not be annotated using "#pragma simd".

The changes in particular:

1. Split the "InParallelFor" flag into an "InParallelFor" and an
   "InSIMD" flag.

2. Unconditionally call "astScheduleDimIsParallel" for its side-effects
   and store the result in "InParallel" for later use.

3. Simplify the condition when a loop is "InnermostParallel".

Fixes llvm.org/PR33153 and llvm.org/PR38073.
------------------------------------------------------------------------

llvm-svn: 347024
2018-11-16 04:24:44 +00:00
Tom Stellard
24d841e026 Merging r344516:
------------------------------------------------------------------------
r344516 | abeserminji | 2018-10-15 07:39:12 -0700 (Mon, 15 Oct 2018) | 12 lines

[mips][micromips] Fix overlaping FDEs error

When compiling static executable for micromips, CFI symbols
are incorrectly labeled as MICROMIPS, which cause
".eh_frame_hdr refers to overlapping FDEs." error.

This patch does not label CFI symbols as MICROMIPS, and FDEs do not
overlap anymore. This patch also exposes another bug, which is fixed
here: https://reviews.llvm.org/D52985

Differential Revision: https://reviews.llvm.org/D52987

------------------------------------------------------------------------

llvm-svn: 347023
2018-11-16 04:22:24 +00:00
Tom Stellard
9a20188b02 Merging r342946:
------------------------------------------------------------------------
r342946 | smaksimovic | 2018-09-24 23:27:49 -0700 (Mon, 24 Sep 2018) | 6 lines

[mips] Correct MUL pattern for mips64

Guard existing pattern with a predicate, introduce a new one for revision 6.

Differential Revision: https://reviews.llvm.org/D51684

------------------------------------------------------------------------

llvm-svn: 346742
2018-11-13 06:06:53 +00:00
Tom Stellard
92a9b7acc3 Merging r342884:
------------------------------------------------------------------------
r342884 | petarj | 2018-09-24 07:14:19 -0700 (Mon, 24 Sep 2018) | 12 lines

[Mips][FastISel] Fix selectBranch on icmp i1

The r337288 tried to fix result of icmp i1 when its input is not sanitized
by falling back to DagISel. While it now produces the correct result for
bit 0, the other bits can still hold arbitrary value which is not supported
by MipsFastISel branch lowering. This patch fixes the issue by falling back
to DagISel in this case.

Patch by Dragan Mladjenovic.

Differential Revision: https://reviews.llvm.org/D52045

------------------------------------------------------------------------

llvm-svn: 346741
2018-11-13 05:58:13 +00:00
Tom Stellard
26d78f3492 Merging r341919:
------------------------------------------------------------------------
r341919 | atanasyan | 2018-09-11 02:57:25 -0700 (Tue, 11 Sep 2018) | 18 lines

[mips] Add a pattern for 64-bit GPR variant of the `rdhwr` instruction

MIPS ISAs start to support third operand for the `rdhwr` instruction
starting from Revision 6. But LLVM generates assembler code with
three-operands version of this instruction on any MIPS64 ISA. The third
operand is always zero, so in case of direct code generation we get
correct code.

This patch fixes the bug by adding an instruction alias. The same alias
already exists for 32-bit ISA.

Ideally, we also need to reject three-operands version of the `rdhwr`
instruction in an assembler code if ISA revision is less than 6. That is
a task for a separate patch.

This fixes PR38861 (https://bugs.llvm.org/show_bug.cgi?id=38861)

Differential revision: https://reviews.llvm.org/D51773
------------------------------------------------------------------------

llvm-svn: 346739
2018-11-13 05:43:07 +00:00
Tom Stellard
e89fa36f68 Merging r341221:
------------------------------------------------------------------------
r341221 | atanasyan | 2018-08-31 08:57:17 -0700 (Fri, 31 Aug 2018) | 12 lines

[mips] Fix `mtc1` and `mfc1` definitions for microMIPS R6

The `mtc1` and `mfc1` definitions in the MipsInstrFPU.td have MMRel,
but do not have StdMMR6Rel tags. When these instructions are emitted
for microMIPS R6 targets, `Mips::MipsR62MicroMipsR6` nor
`Mips::Std2MicroMipsR6` cannot find correct op-codes and as a result the
backend uses mips32 variant of the instructions encoding.

The patch fixes this problem by adding the StdMMR6Rel tag and check
instructions encoding in the test case.

Differential revision: https://reviews.llvm.org/D51482
------------------------------------------------------------------------

llvm-svn: 346737
2018-11-13 05:28:23 +00:00
Tom Stellard
447f344357 Merging r340932:
------------------------------------------------------------------------
r340932 | atanasyan | 2018-08-29 07:54:01 -0700 (Wed, 29 Aug 2018) | 11 lines

[mips] Fix microMIPS unconditional branch offset handling

MipsSEInstrInfo class defines for internal purpose unconditional
branches as Mips::B nad Mips:J even in case of microMIPS code
generation. Under some conditions that leads to the bug - for rather long
branch which fits to Mips jump instruction offset size, but does not fit
to microMIPS jump offset size, we generate 'short' branch and later show
an error 'out of range PC16 fixup' after check in the isBranchOffsetInRange
routine.

Differential revision: https://reviews.llvm.org/D50615
------------------------------------------------------------------------

llvm-svn: 346736
2018-11-13 05:19:01 +00:00
Tom Stellard
b0d060a930 Merging r340931:
------------------------------------------------------------------------
r340931 | atanasyan | 2018-08-29 07:53:55 -0700 (Wed, 29 Aug 2018) | 6 lines

[mips] Involves microMIPS's jump in the analyzable branch set

Involves microMIPS's jump in the analyzable branch set to reduce some
code patterns.

Differential revision: https://reviews.llvm.org/D50613
------------------------------------------------------------------------

llvm-svn: 346735
2018-11-13 05:02:15 +00:00
Tom Stellard
6ea1c152e2 Merging r340927:
------------------------------------------------------------------------
r340927 | vstefanovic | 2018-08-29 07:07:14 -0700 (Wed, 29 Aug 2018) | 14 lines

[mips] Prevent shrink-wrap for BuildPairF64, ExtractElementF64 when they use $sp

For a certain combination of options, BuildPairF64_{64}, ExtractElementF64{_64}
may be expanded into instructions using stack.
Add implicit operand $sp for such cases so that ShrinkWrapping doesn't move
prologue setup below them.

Fixes MultiSource/Benchmarks/MallocBench/cfrac for
'--target=mips-img-linux-gnu -mcpu=mips32r6 -mfpxx -mnan=2008'
and
'--target=mips-img-linux-gnu -mcpu=mips32r6 -mfp64 -mnan=2008 -mno-odd-spreg'.

Differential Revision: https://reviews.llvm.org/D50986

------------------------------------------------------------------------

llvm-svn: 346734
2018-11-13 04:49:21 +00:00
Tom Stellard
dc96c518c1 Bump version to 7.0.1
llvm-svn: 346007
2018-11-02 17:47:32 +00:00
Tom Stellard
204289afe0 Merging r342354:
------------------------------------------------------------------------
r342354 | kristina | 2018-09-16 15:21:59 -0700 (Sun, 16 Sep 2018) | 11 lines

[DebugInfo] Fix build when std::vector::iterator is a pointer

std::vector::iterator type may be a pointer, then
iterator::value_type fails to compile since iterator is not a class,
namespace, or enumeration.

Patch by orivej (Orivej Desh)

Differential Revision: https://reviews.llvm.org/D52142

------------------------------------------------------------------------

llvm-svn: 345923
2018-11-02 02:46:33 +00:00
Tom Stellard
bbaf33edcf Merging r344454, r344455, r344645:
------------------------------------------------------------------------
r344454 | xbolva00 | 2018-10-13 08:21:55 -0700 (Sat, 13 Oct 2018) | 11 lines

[InstCombine] Fixed crash with aliased functions

Summary: Fixes PR39177

Reviewers: spatel, jbuening

Reviewed By: jbuening

Subscribers: jbuening, llvm-commits

Differential Revision: https://reviews.llvm.org/D53129
------------------------------------------------------------------------

------------------------------------------------------------------------
r344455 | xbolva00 | 2018-10-13 08:26:13 -0700 (Sat, 13 Oct 2018) | 2 lines

[NFC] Fixed duplicated test file

------------------------------------------------------------------------

------------------------------------------------------------------------
r344645 | xbolva00 | 2018-10-16 14:18:31 -0700 (Tue, 16 Oct 2018) | 9 lines

[InstCombine] Cleanup libfunc attribute inferring

Reviewers: efriedma

Reviewed By: efriedma

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D53338
------------------------------------------------------------------------

llvm-svn: 345921
2018-11-02 02:26:07 +00:00
Tom Stellard
74c32a1179 Merging r341312:
------------------------------------------------------------------------
r341312 | psmith | 2018-09-03 05:36:32 -0700 (Mon, 03 Sep 2018) | 13 lines

[Aarch64] Fix linker emulation for Aarch64 big endian

This patch fixes target linker emulation for aarch64 big endian.
aarch64_be_linux is not recognized by gnu ld. The equivalent emulation
mode supported by gnu ld is aarch64linuxb.

Patch by: Bharathi Seshadri

Reviewed by: Peter Smith

Differential Revision: https://reviews.llvm.org/D42930

------------------------------------------------------------------------

llvm-svn: 345920
2018-11-02 01:58:07 +00:00
Tom Stellard
32d269695a Merging r345002:
------------------------------------------------------------------------
r345002 | dim | 2018-10-22 22:53:15 -0700 (Mon, 22 Oct 2018) | 41 lines

Don't mess up RelIplt symbols during relocatable processing

Summary:
During upgrading of the FreeBSD source tree with lld 7.0.0, I noticed
that it started complaining about `crt1.o` having an "index past the
end of the symbol table".

Such a symbol table looks approximately like this, viewed with `readelf
-s` (note the `Ndx` field being messed up):

```
Symbol table '.symtab' contains 4 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 SECTION LOCAL  DEFAULT    1
     2: 00000000     0 NOTYPE  WEAK   HIDDEN  RSV[0xffff] __rel_iplt_end
     3: 00000000     0 NOTYPE  WEAK   HIDDEN  RSV[0xffff] __rel_iplt_start
```

At first, it seemed that recent ifunc relocation work had caused this:
<https://reviews.freebsd.org/rS339351>, but it turned out that it was
due to incorrect processing of the object files by lld, when using `-r`
(a.k.a. --relocatable).

Bisecting showed that rL324421 ("Convert a use of Config->Static") was
the commit where this new behavior began.  Simply reverting it solved
the issue, and the `__rel_iplt` symbols had an index of `UND` again.

Looking at Rafael's commit message, I think he simply missed the
possibility of `--relocatable` being in effect, so I have added an
additional check for it.

I also added a simple regression test case.

Reviewers: grimar, ruiu, emaste, espindola

Reviewed By: ruiu

Subscribers: arichardson, krytarowski, llvm-commits

Differential Revision: https://reviews.llvm.org/D53515
------------------------------------------------------------------------

llvm-svn: 345739
2018-10-31 17:14:17 +00:00
Tom Stellard
8beaae2363 Merging r343669:
------------------------------------------------------------------------
r343669 | grimar | 2018-10-03 02:59:08 -0700 (Wed, 03 Oct 2018) | 6 lines

[ELF] - Fix BB after r343668

This stops testing the value of .rela.plt section offset.

Also makes _start global to eliminate
'cannot find entry symbol _start' warning.
------------------------------------------------------------------------

llvm-svn: 345732
2018-10-31 15:58:47 +00:00
Tom Stellard
f0ed63b765 Merging r341778:
------------------------------------------------------------------------
r341778 | rsmith | 2018-09-09 23:35:32 -0700 (Sun, 09 Sep 2018) | 5 lines

PR33222: Require the declared return type not the actual return type to
match when checking for redeclaration of a function template.

This properly handles differences in deduced return types, particularly
when performing redeclaration checks for a friend function template.
------------------------------------------------------------------------

llvm-svn: 345412
2018-10-26 17:59:43 +00:00
Tom Stellard
ea49dcd184 Merging r341775:
------------------------------------------------------------------------
r341775 | rsmith | 2018-09-09 22:32:13 -0700 (Sun, 09 Sep 2018) | 2 lines

Part of PR33222: defer enforcing return type mismatch for dependent
friend function declarations of class templates.
------------------------------------------------------------------------

llvm-svn: 345409
2018-10-26 17:32:52 +00:00
Tom Stellard
9e981fb6e1 Merging r344325:
------------------------------------------------------------------------
r344325 | evgeny777 | 2018-10-12 00:24:02 -0700 (Fri, 12 Oct 2018) | 4 lines

[ThinLTO] Don't import GV which contains blockaddress

Differential revision: https://reviews.llvm.org/D53139

------------------------------------------------------------------------

llvm-svn: 345401
2018-10-26 16:52:32 +00:00
Tom Stellard
1696eef2ac Merging r340025:
------------------------------------------------------------------------
r340025 | erichkeane | 2018-08-17 06:43:39 -0700 (Fri, 17 Aug 2018) | 8 lines

Fix for bug 38508 - Don't do PCH processing when only generating preprocessor output

This clang-cl driver change removes the PCH options when we are only generating
preprocessed output. This is similar to the behavior of Y-.

Patch by: mikerice
Differential Revision: https://reviews.llvm.org/D50640

------------------------------------------------------------------------

llvm-svn: 345311
2018-10-25 20:41:01 +00:00
Tom Stellard
ccf7f5115e Merging r339424:
------------------------------------------------------------------------
r339424 | hans | 2018-08-10 04:40:50 -0700 (Fri, 10 Aug 2018) | 1 line

clang-cl: accept -fcrash-diagnostics-dir=
------------------------------------------------------------------------

llvm-svn: 345304
2018-10-25 19:37:31 +00:00
Tom Stellard
6d5c2a5a85 Merging r342897:
------------------------------------------------------------------------
r342897 | mgorny | 2018-09-24 09:10:25 -0700 (Mon, 24 Sep 2018) | 5 lines

[python] [tests] Update test_code_completion

Update expected completions to match output generated by clang-7.0.

Differential Revision: https://reviews.llvm.org/D50171
------------------------------------------------------------------------

llvm-svn: 345000
2018-10-23 05:18:59 +00:00
Tom Stellard
a8b61d167f Merging r344368:
------------------------------------------------------------------------
r344368 | ruiu | 2018-10-12 10:07:32 -0700 (Fri, 12 Oct 2018) | 10 lines

[lld] Add more complete support for the INCLUDE command.

Patch by Ian Tessier.

This change adds INCLUDE support to the MEMORY and SECTION commands, and
to output sections, as per:

https://sourceware.org/binutils/docs/ld/File-Commands.html#File-Commands

Differential Revision: https://reviews.llvm.org/D52951
------------------------------------------------------------------------

llvm-svn: 344926
2018-10-22 17:45:40 +00:00
Tom Stellard
b8dce5ad76 Merging r343668:
------------------------------------------------------------------------
r343668 | grimar | 2018-10-03 02:33:00 -0700 (Wed, 03 Oct 2018) | 20 lines

[ELF] - Do not forget to include to .dymsym symbols that were converted to Defined.

This is the fix for
"Bug 39104 - LLD links incorrect ELF executable if version script contains "local: *;"
(https://bugs.llvm.org/show_bug.cgi?id=39104).

The issue happens when we have non-PIC program call to function in a shared library.
(for example, the PR above has R_X86_64_PC32 relocation against __libc_start_main)

LLD converts symbol to Defined in that case with the use of replaceWithDefined()

The issue is that after above we create a broken relocation because do not
include the symbol into .dynsym.

That happens when the version script is used because we treat the symbol as
STB_LOCAL if the following condition match:
VersionId == VER_NDX_LOCAL && isDefined() and do not include it to
.dynsym because of that. Patch fixes the issue.

Differential revision: https://reviews.llvm.org/D52724
------------------------------------------------------------------------

llvm-svn: 344925
2018-10-22 17:44:17 +00:00
Tom Stellard
8e5d7e5115 Merging r344824:
------------------------------------------------------------------------
r344824 | ctopper | 2018-10-19 18:30:00 -0700 (Fri, 19 Oct 2018) | 14 lines

[X86] When checking the bits in cpu_features for function multiversioning dispatcher in the resolver, make sure all the required bits are set. Not just one of them

Summary:
The multiversioning code repurposed the code from __builtin_cpu_supports for checking if a single feature is enabled. That code essentially performed (_cpu_features & (1 << C)) != 0. But with the multiversioning path, the mask is no longer guaranteed to be a power of 2. So we return true anytime any one of the bits in the mask is set not just all of the bits.

The correct check is (_cpu_features & mask) == mask

Reviewers: erichkeane, echristo

Reviewed By: echristo

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D53460
------------------------------------------------------------------------

llvm-svn: 344923
2018-10-22 17:31:01 +00:00
Tom Stellard
f2ee78ccdf Merging r344264:
------------------------------------------------------------------------
r344264 | mstorsjo | 2018-10-11 10:45:51 -0700 (Thu, 11 Oct 2018) | 8 lines

[COFF] Set proper pointer size alignment for LocalImportChunk

When these are accessed with load/store instructions on ARM64,
it becomes strictly necessary to have them properly aligned.

This fixes PR39228.

Differential Revision: https://reviews.llvm.org/D53128
------------------------------------------------------------------------

llvm-svn: 344920
2018-10-22 16:52:14 +00:00
Tom Stellard
dfebe57343 Merging r342461:
------------------------------------------------------------------------
r342461 | devnexen | 2018-09-18 03:31:10 -0700 (Tue, 18 Sep 2018) | 10 lines

[Xray] llvm-xray fix possible segfault

top argument when superior to the instrumentated code list capacity can lead to a segfault.

Reviewers: dberris

Reviewed By: dberris

Differential Revision: https://reviews.llvm.org/D52224

------------------------------------------------------------------------

llvm-svn: 344918
2018-10-22 16:37:14 +00:00
Tom Stellard
0447cd66a0 Merging r342815:
------------------------------------------------------------------------
r342815 | ericwf | 2018-09-22 12:22:36 -0700 (Sat, 22 Sep 2018) | 14 lines

Fix incorrectly aligned exceptions in 32 bit builds.

This patch fixes a bug where exceptions in 32 bit builds
would be incorrectly aligned because malloc only provides 8 byte aligned
memory where 16 byte alignment is needed.

This patch makes libc++abi correctly use posix_memalign when it's
available. This requires defining _LIBCPP_BUILDING_LIBRARY so that
libc++ only defines _LIBCPP_HAS_NO_ALIGNED_ALLOCATION when libc doesn't
support it and not when aligned new/delete are disable for other
reasons.

This bug somehow made it into the 7.0 release, making it a regression.
Therefore this patch should be included in the next dot release.
------------------------------------------------------------------------

llvm-svn: 344917
2018-10-22 16:29:48 +00:00
Tom Stellard
cddf73ef26 Merging r343373:
------------------------------------------------------------------------
r343373 | rksimon | 2018-09-29 06:25:22 -0700 (Sat, 29 Sep 2018) | 3 lines

[X86][SSE] Fixed issue with v2i64 variable shifts on 32-bit targets

The shift amount might have peeked through a extract_subvector, altering the number of vector elements in the 'Amt' variable - so we were incorrectly calculating the ratio when peeking through bitcasts, resulting in incorrectly detecting splats.
------------------------------------------------------------------------

llvm-svn: 344810
2018-10-19 19:56:57 +00:00
Tom Stellard
80adf40949 Merging r343428:
------------------------------------------------------------------------
r343428 | ctopper | 2018-09-30 16:43:30 -0700 (Sun, 30 Sep 2018) | 3 lines

[X86] Change an llvm_unreachable to a report_fatal_error so the optimizer will stop making us reach the other report_fatal_error in this function.

There's a conditional report_fatal_error just above this llvm_unreachable. The optimizer when seeing the unreachable removes the conditional and just makes any other error trigger the existing report_fatal_error.
------------------------------------------------------------------------

llvm-svn: 344805
2018-10-19 19:14:17 +00:00
Tom Stellard
78605c68f3 Merging r343443:
------------------------------------------------------------------------
r343443 | ctopper | 2018-10-01 00:08:41 -0700 (Mon, 01 Oct 2018) | 9 lines

[X86] Stop X86DomainReassignment from creating copies between GR8/GR16 physical registers and k-registers.

We can only copy between a k-register and a GR32/GR64 register.

This patch detects that the copy will be illegal and prevents the domain reassignment from happening for that closure.

This probably isn't the best fix, and we should probably figure out how to handle this correctly.

Fixes PR38803.
------------------------------------------------------------------------

llvm-svn: 344804
2018-10-19 19:11:17 +00:00
Tom Stellard
8c4d80af1f Merging r343347:
------------------------------------------------------------------------
r343347 | cmatthews | 2018-09-28 10:55:18 -0700 (Fri, 28 Sep 2018) | 4 lines

make lit builtins a package

cat.py is not being installed when lit is installed from source. So
tests that use the internal shell fail when using cat.
------------------------------------------------------------------------

llvm-svn: 344792
2018-10-19 17:48:37 +00:00
Rui Ueyama
00b161b897 Update release notes for lld 7.
llvm-svn: 342187
2018-09-13 21:50:59 +00:00
Martin Storsjo
d18bc8eb29 Clarify the wording for the state of the lld/MinGW target
llvm-svn: 341976
2018-09-11 18:34:33 +00:00
Rui Ueyama
383fa52f0f Update release notes to say that lld/MinGW is production-ready.
llvm-svn: 341936
2018-09-11 13:27:39 +00:00
Hans Wennborg
d15c758f14 ReleaseNotes: some notes from Andres Freund
llvm-svn: 341916
2018-09-11 08:39:31 +00:00
Hans Wennborg
e37bc8295d ReleaseNotes: fixes
llvm-svn: 341913
2018-09-11 08:05:44 +00:00
Hans Wennborg
5de718097c ReleaseNotes.rst: Add Zig to External Open Source Projects Using LLVM 7
Differential revision: https://reviews.llvm.org/D51118

llvm-svn: 341911
2018-09-11 07:52:29 +00:00
Rui Ueyama
39b75e9e84 Update release notes for lld 7.0.
llvm-svn: 341890
2018-09-11 02:14:11 +00:00
Hans Wennborg
78bdb22298 docs: drop doxygen link; it doesn't work
llvm-svn: 341829
2018-09-10 14:15:12 +00:00
Hans Wennborg
f0e9472a47 docs: drop another in-progress warning
llvm-svn: 341828
2018-09-10 14:14:03 +00:00
Hans Wennborg
494f9e4c0d ReleaseNotes: tiny fix
llvm-svn: 341805
2018-09-10 12:14:41 +00:00
Hans Wennborg
1db9b3efdf ReleaseNotes: minor tweaks
llvm-svn: 341804
2018-09-10 12:08:00 +00:00
Hans Wennborg
3472e2a5a5 Merging r341642:
------------------------------------------------------------------------
r341642 | tnorthover | 2018-09-07 11:21:25 +0200 (Fri, 07 Sep 2018) | 8 lines

ARM: fix Thumb2 CodeGen for ldrex with folded frame-index.

Because t2LDREX (& t2STREX) were marked as AddrModeNone, but did allow a
FrameIndex operand, rewriteT2FrameIndex asserted. This gives them a
proper addressing-mode and tells the rewriter about it so that encodable
offsets are exploited and others are rejected.

Should fix PR38828.
------------------------------------------------------------------------

llvm-svn: 341783
2018-09-10 08:11:26 +00:00
Hans Wennborg
3065b0a70b Merging r341670 and r341672:
------------------------------------------------------------------------
r341670 | tstellar | 2018-09-07 17:42:01 +0200 (Fri, 07 Sep 2018) | 15 lines

MachO: Fix out-of-bounds memory access in getString16

Summary:
This fixes the following tests when gcc is compiled with gcc8:

lld :: mach-o/do-not-emit-unwind-fde-arm64.yaml
lld :: mach-o/eh-frame-relocs-arm64.yaml

llvm.org/PR38096

Reviewers: lhames, kledzik, javed.absar

Subscribers: kristof.beyls, llvm-commits

Differential Revision: https://reviews.llvm.org/D51547
------------------------------------------------------------------------

------------------------------------------------------------------------
r341672 | tstellar | 2018-09-07 17:51:52 +0200 (Fri, 07 Sep 2018) | 3 lines

MachO: Change getString16() back to inline function

This was accidentally changed in r341670.
------------------------------------------------------------------------

llvm-svn: 341780
2018-09-10 07:55:48 +00:00
Hans Wennborg
0e44dc22ff Regenerate DiagnosticsReference.rst
llvm-svn: 341665
2018-09-07 14:38:20 +00:00
Hans Wennborg
89e6185feb Remove ReleaseNotes as they were empty
llvm-svn: 341664
2018-09-07 14:26:49 +00:00
Hans Wennborg
e0f0bdd4d0 ReleaseNotes: tidy up for the release
llvm-svn: 341663
2018-09-07 14:24:36 +00:00
Hans Wennborg
69c7f488bf ReleaseNotes: tidy up for the release
llvm-svn: 341662
2018-09-07 14:21:33 +00:00
Hans Wennborg
0d7b2cb16c ReleaseNotes: tidy up for the release
llvm-svn: 341661
2018-09-07 14:18:34 +00:00
Hans Wennborg
f464f9b322 ReleaseNotes: tidy up for the release
llvm-svn: 341640
2018-09-07 09:20:15 +00:00
Hans Wennborg
d2647fa6f2 Merging r341512:
------------------------------------------------------------------------
r341512 | ctopper | 2018-09-06 04:03:14 +0200 (Thu, 06 Sep 2018) | 7 lines

[X86][Assembler] Allow %eip as a register in 32-bit mode for .cfi directives.

This basically reverts a change made in r336217, but improves the text of the error message for not allowing IP-relative addressing in 32-bit mode.

Fixes PR38826.

Patch by Iain Sandoe.
------------------------------------------------------------------------

llvm-svn: 341530
2018-09-06 08:58:13 +00:00
Hans Wennborg
f1c57fe859 Merging r340609:
------------------------------------------------------------------------
r340609 | ldionne | 2018-08-24 16:10:28 +0200 (Fri, 24 Aug 2018) | 13 lines

[libc++] Fix handling of negated character classes in regex

Summary:
This commit fixes a regression introduced in r316095, where we don't match
inverted character classes when there's no negated characrers in the []'s.

rdar://problem/43060054

Reviewers: mclow.lists, timshen, EricWF

Subscribers: christof, dexonsmith, cfe-commits

Differential Revision: https://reviews.llvm.org/D50534
------------------------------------------------------------------------

llvm-svn: 341529
2018-09-06 08:54:44 +00:00
Hans Wennborg
2359633b04 Merging r341442:
------------------------------------------------------------------------
r341442 | bcain | 2018-09-05 04:15:54 +0200 (Wed, 05 Sep 2018) | 8 lines

Add glibc_prereq to platform limits mmsghdr

sendmmsg requires glibc >= 2.14.

Fixes PR38589.

Review: https://reviews.llvm.org/D51538

------------------------------------------------------------------------

llvm-svn: 341524
2018-09-06 08:19:33 +00:00
Hans Wennborg
fbe05633b7 Merging r341416:
------------------------------------------------------------------------
r341416 | annat | 2018-09-05 00:12:23 +0200 (Wed, 05 Sep 2018) | 11 lines

[LV] First order recurrence phis should not be treated as uniform

This is fix for PR38786.
First order recurrence phis were incorrectly treated as uniform,
which caused them to be vectorized as uniform instructions.

Patch by Ayal Zaks and Orivej Desh!

Reviewed by: Anna

Differential Revision: https://reviews.llvm.org/D51639
------------------------------------------------------------------------

llvm-svn: 341523
2018-09-06 08:16:34 +00:00
Hans Wennborg
3f83c2fa74 ReleaseNotes: ARM SVE asm/disasm support
llvm-svn: 341522
2018-09-06 08:11:04 +00:00
Hans Wennborg
d8c3a2aa7e ReleaseNotes: libc++ _LIBCPP_HIDE_FROM_ABI_PER_TU
llvm-svn: 341521
2018-09-06 08:09:39 +00:00
Hans Wennborg
4e3ef6368c ReleaseNotes: support for new-pm passes in the opt tool
llvm-svn: 341520
2018-09-06 08:03:05 +00:00
Hans Wennborg
90699f8b7e ReleaseNotes for PowerPC
Patch by Lei Huang!

llvm-svn: 341453
2018-09-05 08:07:31 +00:00
Hans Wennborg
3d3c7c2e04 Merging r339253:
------------------------------------------------------------------------
r339253 | psmith | 2018-08-08 16:50:33 +0200 (Wed, 08 Aug 2018) | 7 lines

Add missing REQUIRES x86 to tests.

Add REQUIRES to tests that fail when an x86 backend is not present.

Differential Revision: https://reviews.llvm.org/D50440


------------------------------------------------------------------------

llvm-svn: 341367
2018-09-04 14:17:36 +00:00
Hans Wennborg
9f802dded8 ReleaseNotes: tiny tweak
llvm-svn: 341359
2018-09-04 11:43:30 +00:00
David Chisnall
ddeced087a Add release notes for the new GNUstep Objective-C ABI.
llvm-svn: 341355
2018-09-04 10:40:24 +00:00
David Chisnall
3ec022d029 Disable the GNUstep v2 ABI on Windows.
The code remains so that we can potentially reenable it in a point
release, but the driver will reject it.  Several issues were raised
during testing that made it clear that this was not quite ready for
general consumption.

Approved by: Hans Wennborg

llvm-svn: 341354
2018-09-04 10:40:19 +00:00
Hans Wennborg
64b6c7b5f9 Merging r340959:
------------------------------------------------------------------------
r340959 | mareko | 2018-08-29 22:03:00 +0200 (Wed, 29 Aug 2018) | 9 lines

AMDGPU: Handle 32-bit address wraparounds for SMRD opcodes

Summary: This fixes GPU hangs with OpenGL bindless handle arithmetic.

Reviewers: arsenm, nhaehnle

Subscribers: kzhuravl, jvesely, wdng, yaxunl, dstuttard, tpr, t-tye, llvm-commits

Differential Revision: https://reviews.llvm.org/D51203
------------------------------------------------------------------------

llvm-svn: 341351
2018-09-04 09:29:18 +00:00
Hans Wennborg
95cde841ed Merging r341244:
------------------------------------------------------------------------
r341244 | tstellar | 2018-08-31 22:15:31 +0200 (Fri, 31 Aug 2018) | 11 lines

lit: Use sys.executable for executing builtin commands

Summary:
The python executable may not exist on all systems so use sys.executable
instead.

Reviewers: ddunbar, stella.stamenova

Subscribers: delcypher, llvm-commits

Differential Revision: https://reviews.llvm.org/D51511
------------------------------------------------------------------------

llvm-svn: 341349
2018-09-04 09:21:35 +00:00
Hans Wennborg
8efd177122 Merging r341094:
------------------------------------------------------------------------
r341094 | efriedma | 2018-08-30 20:59:24 +0200 (Thu, 30 Aug 2018) | 11 lines

[SROA] Fix alignment for uses of PHI nodes.

Splitting an alloca can decrease the alignment of GEPs into the
partition.  Normally, rewriting accounts for this, but the code was
missing for uses of PHI nodes and select instructions.

Fixes https://bugs.llvm.org/show_bug.cgi?id=38707 .

Differential Revision: https://reviews.llvm.org/D51335


------------------------------------------------------------------------

llvm-svn: 341220
2018-08-31 15:53:05 +00:00
Simon Atanasyan
8f8e7688cc [docs][mips] 7.0 Release notes
Differential revision: https://reviews.llvm.org/D51355

llvm-svn: 341203
2018-08-31 11:27:14 +00:00
Simon Atanasyan
3c08d65383 [docs][mips] Clang 7.0 Release notes
Differential revision: https://reviews.llvm.org/D51356

llvm-svn: 341201
2018-08-31 11:25:04 +00:00
Hans Wennborg
db7876c1bc Merging r340900:
------------------------------------------------------------------------
r340900 | hans | 2018-08-29 08:55:27 +0200 (Wed, 29 Aug 2018) | 6 lines

LoopSink: Don't sink into blocks without an insertion point (PR38462)

In the PR, LoopSink was trying to sink into a catchswitch block, which
doesn't have a valid insertion point.

Differential Revision: https://reviews.llvm.org/D51307
------------------------------------------------------------------------

llvm-svn: 341048
2018-08-30 09:34:31 +00:00
Hans Wennborg
9a5180794b Merging r340751:
------------------------------------------------------------------------
r340751 | hans | 2018-08-27 17:55:39 +0200 (Mon, 27 Aug 2018) | 7 lines

Use a lambda for calls to ::open in RetryAfterSignal

In Bionic, open can be overloaded for _FORTIFY_SOURCE support, causing
compile errors of RetryAfterSignal due to overload resolution. Wrapping
the call in a lambda avoids this.

Based on a patch by Chih-Wei Huang <cwhuang@linux.org.tw>!
------------------------------------------------------------------------

llvm-svn: 341044
2018-08-30 09:31:52 +00:00
Hans Wennborg
55aaea2e2e Merging r340417:
------------------------------------------------------------------------
r340417 | hakzsam | 2018-08-22 18:08:48 +0200 (Wed, 22 Aug 2018) | 14 lines

AMDGPU: bump AS.MAX_COMMON_ADDRESS to 6 since 32-bit addr space

32-bit constant address space is declared as 6, so the
maximum number of address spaces is 6, not 5.

Fixes "LLVM ERROR: Pointer address space out of range".

v5: rename MAX_COMMON_ADDRESS to MAX_AMDGPU_ADDRESS
v4: - fix compilation issues
    - fix out of bounds access
v3: use static_assert()
v2: add a very simple test for 32-bit addr space

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106630
------------------------------------------------------------------------

llvm-svn: 341041
2018-08-30 08:48:13 +00:00
Hans Wennborg
612dde51dc Merging r340416:
------------------------------------------------------------------------
r340416 | hakzsam | 2018-08-22 18:08:43 +0200 (Wed, 22 Aug 2018) | 8 lines

AMDGPU: fix existing alias rules for constant and global

Constant and global may alias, also one rules table wasn't
ordered correctly.

Pinpointed by Matt.

v2: add a test with swapped parameters
------------------------------------------------------------------------

llvm-svn: 341040
2018-08-30 08:46:10 +00:00
Hans Wennborg
dc2d638493 Merging r340455:
------------------------------------------------------------------------
r340455 | yhs | 2018-08-22 23:21:03 +0200 (Wed, 22 Aug 2018) | 38 lines

bpf: fix an assertion in BPFAsmBackend applyFixup()

Fix bug https://bugs.llvm.org/show_bug.cgi?id=38643

In BPFAsmBackend applyFixup(), there is an assertion for FixedValue to be 0.
This may not be true, esp. for optimiation level 0.
For example, in the above bug, for the following two
static variables:
  @bpf_map_lookup_elem = internal global i8* (i8*, i8*)*
      inttoptr (i64 1 to i8* (i8*, i8*)*), align 8
  @bpf_map_update_elem = internal global i32 (i8*, i8*, i8*, i64)*
      inttoptr (i64 2 to i32 (i8*, i8*, i8*, i64)*), align 8

The static variable @bpf_map_update_elem will have a symbol
offset of 8 and a FK_SecRel_8 with FixupValue 8 will cause
the assertion if llvm is built with -DLLVM_ENABLE_ASSERTIONS=ON.

The above relocations will not exist if the program is compiled
with optimization level -O1 and above as the compiler optimizes
those static variables away. In the below error message, -O2
is suggested as this is the common practice.

Note that FixedValue = 0 in applyFixup() does exist and is valid,
e.g., for the global variable my_map in the above bug. The bpf
loader will process them properly for map_id's before loading
the program into the kernel.

The static variables, which are not optimized away by compiler,
may have FK_SecRel_8 relocation with non-zero FixedValue.

The patch removed the offending assertion and will issue
a hard error as below if the FixedValue in applyFixup()
is not 0.
  $ llc -march=bpf -filetype=obj fixup.ll
  LLVM ERROR: Unsupported relocation: try to compile with -O2 or above,
      or check your static variable usage

Signed-off-by: Yonghong Song <yhs@fb.com>
------------------------------------------------------------------------

llvm-svn: 341038
2018-08-30 08:42:29 +00:00
Hans Wennborg
8f50cb6b5a Merging r340820:
------------------------------------------------------------------------
r340820 | uabelho | 2018-08-28 14:40:11 +0200 (Tue, 28 Aug 2018) | 34 lines

[CloneFunction] Constant fold terminators before checking single predecessor

Summary:
This fixes PR31105.

There is code trying to delete dead code that does so by e.g. checking if
the single predecessor of a block is the block itself.

That check fails on a block like this
 bb:
   br i1 undef, label %bb, label %bb
since that has two (identical) predecessors.

However, after the check for dead blocks there is a call to
ConstantFoldTerminator on the basic block, and that call simplifies the
block to
 bb:
   br label %bb

Therefore we now do the call to ConstantFoldTerminator before the check if
the block is dead, so it can realize that it really is.

The original behavior lead to the block not being removed, but it was
simplified as above, and then we did a call to
    Dest->replaceAllUsesWith(&*I);
with old and new being equal, and an assertion triggered.

Reviewers: chandlerc, fhahn

Reviewed By: fhahn

Subscribers: eraman, llvm-commits

Differential Revision: https://reviews.llvm.org/D51280
------------------------------------------------------------------------

llvm-svn: 341037
2018-08-30 08:35:03 +00:00
Hans Wennborg
7e8fa65f14 Merging r340839:
------------------------------------------------------------------------
r340839 | bcain | 2018-08-28 18:23:39 +0200 (Tue, 28 Aug 2018) | 14 lines

[debuginfo] generate debug info with asm+.file

Summary:
For assembly input files, generate debug info even when the .file
directive is present, provided it does not include a file-number
argument.  Fixes PR38695.

Reviewers: probinson, sidneym

Subscribers: aprantl, hiraditya, JDevlieghere, llvm-commits

Differential Revision: https://reviews.llvm.org/D51315


------------------------------------------------------------------------

llvm-svn: 341036
2018-08-30 08:30:33 +00:00
Hans Wennborg
a3b989e1f0 Merging r338877, r338911 and r339165:
------------------------------------------------------------------------
r338877 | nico | 2018-08-03 14:00:12 +0200 (Fri, 03 Aug 2018) | 19 lines

lld-link: Fix subsystem inference for non-console apps on 32-bit, and fix entry point inference on 32-bit with /nodefaultlib

LinkerDriver::inferSubsystem() used to do Symtab->findUnderscore("WinMain"),
but WinMain is stdcall in 32-bit and is hence is called _WinMain@16. Instead,
Symtab->findMangle(mangle("WinMain")) needs to be called.

But since LinkerDriver::inferSubsystem() and LinkerDriver::findDefaultEntry()
both need to call this, introduce a common helper function for this and call it
from both places. (Also call it for "main" for consistency, even though
findUnderscore() is enough for main since that's __cdecl on 32-bit).

This also exposed a bug for /nodefaultlib entrypoint inference: The code here
called findMangle(Sym) instead of findMangle(mangle(Sym)), again doing the
wrong thing on 32-bit. Fix that too.

While here, make Driver::mangle() a static free function.

https://reviews.llvm.org/D50184

------------------------------------------------------------------------

------------------------------------------------------------------------
r338911 | nico | 2018-08-03 20:32:44 +0200 (Fri, 03 Aug 2018) | 7 lines

lld-link: Simplify LinkerDriver::findDefaultEntry()

No intended behavior change. Not repeating the CRTStartup names makes fixing
PR36523 simpler.

https://reviews.llvm.org/D50253

------------------------------------------------------------------------

------------------------------------------------------------------------
r339165 | nico | 2018-08-07 21:10:28 +0200 (Tue, 07 Aug 2018) | 26 lines

lld-link: Take /SUBSYSTEM into account for automatic /ENTRY detection.

If /subsystem:windows is passed, link.exe only looks for WinMain and wWinMain,
and if /subsystem:console is passed it only looks for main and wmain. lld-link
used to look for all 4 in both cases. This patch makes lld-link match
link.exe's behavior.

This requires that the subsystem is known by the time findDefaultEntry() gets
called. findDefaultEntry() is called before the main link loop, so that the
loop can mark the entry point as undefined. That means inferSubsystem() has to
be called above the main loop as well. This in turn means /subsystem: from
.drectve sections only has an effect on entry point inference for obj files
passed to lld-link directly (and not in obj files found later in .lib files).
link.exe seems to ignore /subsystem: for obj files from lib files completely
(while in lld it's ignored only for entry point detection but it still
overrides /subsystem: flags passed on the command line for the value that gets
written in the output file).

Also, if the subsytem isn't needed (e.g. when only writing a /def: lib file and
not writing a coff file), link.exe doesn't complain if the subsystem isn't
known, so both subsystem and entry point handling should be below the early
return lld has for that case.

Fixes PR36523.
https://reviews.llvm.org/D50316

------------------------------------------------------------------------

llvm-svn: 341035
2018-08-30 08:25:34 +00:00
Hans Wennborg
fd068d62a0 Merging r340823:
------------------------------------------------------------------------
r340823 | marshall | 2018-08-28 15:29:30 +0200 (Tue, 28 Aug 2018) | 1 line

Use addressof instead of operator& in make_shared. Fixes PR38729. As a drive-by, make the same change in raw_storage_iterator (twice).
------------------------------------------------------------------------

llvm-svn: 341034
2018-08-30 08:19:15 +00:00
Anastasia Stulova
97ded321c3 [Docs] Release notes for OpenCL
Differential Revision: https://reviews.llvm.org/D51212

llvm-svn: 340910
2018-08-29 10:30:35 +00:00
Simon Atanasyan
7c9d3c67a4 [docs][mips] Add MIPS specific release notes for LLD 7.0
Differential revision: https://reviews.llvm.org/D51309

llvm-svn: 340803
2018-08-28 08:25:53 +00:00
Hans Wennborg
1a8a05a1c0 Merging r340758 and r340769:
------------------------------------------------------------------------
r340758 | vitalybuka | 2018-08-27 19:26:28 +0200 (Mon, 27 Aug 2018) | 5 lines

Revert "[lsan] Do not check for leaks in the forked process"

Users need leak reports in forks.

This reverts commit r334036.
------------------------------------------------------------------------

------------------------------------------------------------------------
r340769 | vitalybuka | 2018-08-27 21:15:05 +0200 (Mon, 27 Aug 2018) | 3 lines

[lsan] Check that leak sanitizer works in the forked process

Regression test for PR38698
------------------------------------------------------------------------

llvm-svn: 340801
2018-08-28 08:10:27 +00:00
Hans Wennborg
21f6f5c987 Merging r340641:
------------------------------------------------------------------------
r340641 | stefanp | 2018-08-24 21:38:29 +0200 (Fri, 24 Aug 2018) | 9 lines

[Exception Handling] Unwind tables are required for all functions that have an EH personality.

This patch is for defect:
https://bugs.llvm.org/show_bug.cgi?id=32611

Functions may require unwind tables even if they are marked with the attribute
nounwind. Any function with an EH personality may require an unwind table.

Differential Revision: https://reviews.llvm.org/D50987
------------------------------------------------------------------------

llvm-svn: 340731
2018-08-27 10:05:36 +00:00
Hans Wennborg
cbd4a17454 Merging r340376:
------------------------------------------------------------------------
r340376 | steveire | 2018-08-22 03:11:18 +0200 (Wed, 22 Aug 2018) | 7 lines

Update the docs for using LLVM toolset in Visual Studio

Reviewers: hans

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D51079
------------------------------------------------------------------------

llvm-svn: 340730
2018-08-27 09:51:13 +00:00
Hans Wennborg
e89d1857ed Merging r340691:
------------------------------------------------------------------------
r340691 | codafi | 2018-08-25 21:54:39 +0200 (Sat, 25 Aug 2018) | 11 lines

[C-API][DIBuilder] Use NameLen in LLVMDIBuilderCreateParameterVariable

Summary: NameLen wasn't being used and caused the parameters in gdb to very long, in my case, crashes in others. Please also perform the correct magical incarnations to have this be applied to the LLVM 7 branch.

Reviewers: whitequark, CodaFi

Reviewed By: CodaFi

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D51141
------------------------------------------------------------------------

llvm-svn: 340724
2018-08-27 08:41:29 +00:00
Hans Wennborg
1a530a1bae Merging r340666:
------------------------------------------------------------------------
r340666 | hans | 2018-08-25 00:46:33 +0200 (Sat, 25 Aug 2018) | 21 lines

Revert r323281 "Adjust MaxAtomicInlineWidth for i386/i486 targets."

As reported on http://lists.llvm.org/pipermail/cfe-dev/2018-August/058760.html,
this broke i386-freebsd11 due to its lack of atomic 64 bit primitives.

While that's not really this commit's fault, let's revert back to the old
behaviour until this can be fixed. This means generating cmpxchg8b etc for i386
and i486 which don't technically support those, but that's been the behaviour
for a long time, so a little longer probably doesn't hurt that much.

> Adjust MaxAtomicInlineWidth for i386/i486 targets.
>
> This is to fix the bug reported in https://bugs.llvm.org/show_bug.cgi?id=34347#c6.
> Currently, all  MaxAtomicInlineWidth of x86-32 targets are set to 64. However,
> i386 doesn't support any cmpxchg related instructions. i486 only supports cmpxchg.
> So in this patch MaxAtomicInlineWidth is reset as follows:
> For i386, the MaxAtomicInlineWidth should be 0 because no cmpxchg is supported.
> For i486, the MaxAtomicInlineWidth should be 32 because it supports cmpxchg.
> For others 32 bits x86 cpu, the MaxAtomicInlineWidth should be 64 because of cmpxchg8b.
>
> Differential Revision: https://reviews.llvm.org/D42154
------------------------------------------------------------------------

llvm-svn: 340667
2018-08-24 22:49:44 +00:00
Hans Wennborg
d2b33338a5 Merging r340544:
------------------------------------------------------------------------
r340544 | epilk | 2018-08-23 19:08:02 +0200 (Thu, 23 Aug 2018) | 3 lines

Comment out #define __cpp_lib_node_extract, we only support half of that functionality

Differential revision: https://reviews.llvm.org/D51172
------------------------------------------------------------------------

llvm-svn: 340662
2018-08-24 22:16:24 +00:00
Hans Wennborg
623c252055 Merging r339667:
------------------------------------------------------------------------
r339667 | theraven | 2018-08-14 12:04:36 +0200 (Tue, 14 Aug 2018) | 11 lines

Add a stub mangling for ObjC selectors in the Microsoft ABI.

This mangling is used only for outlined SEH finally blocks, which have
internal linkage.

This fixes the failure of CodeGenObjC/2007-04-03-ObjcEH.m on builds with
expensive checks enabled, on Windows.  This test should probably be
specifying a triple: it currently picks up whatever the host environment
is using.  Unfortunately, I have no idea what it is trying to test,
because it contains no comments and predates Clang having working
Objective-C IR generation.
------------------------------------------------------------------------

llvm-svn: 340437
2018-08-22 18:44:16 +00:00
Hans Wennborg
780e7970fe Merging r340406:
------------------------------------------------------------------------
r340406 | ericwf | 2018-08-22 15:29:52 +0200 (Wed, 22 Aug 2018) | 12 lines

Attempt to unbreak filesystem tests on certain linux distros.

On some platforms clock_gettime is in librt, which we don't
link by default when building the tests. However it is required
by the filesystem tests.

This patch introduces a workaround which links librt whenever
the filesystem tests are enabled. The workaround should later
be replaced with a patch that selectively links both libc++fs
and librt only when building filesystem specific tests. However,
the way the test configuration is set up right now, this is
non-trivial.
------------------------------------------------------------------------

llvm-svn: 340419
2018-08-22 16:39:24 +00:00
Hans Wennborg
7642c02fae Notify pending API removal in the release notes
Patch by Stephen Kelly.

Differential Revision: https://reviews.llvm.org/D51069

llvm-svn: 340375
2018-08-22 00:53:19 +00:00
Hans Wennborg
3b7811f644 Merging r340303:
------------------------------------------------------------------------
r340303 | ctopper | 2018-08-21 19:15:33 +0200 (Tue, 21 Aug 2018) | 9 lines

[BypassSlowDivision] Teach bypass slow division not to interfere with div by constant where constants have been constant hoisted, but not moved from their basic block

DAGCombiner doesn't pay attention to whether constants are opaque before doing the div by constant optimization. So BypassSlowDivision shouldn't introduce control flow that would make DAGCombiner unable to see an opaque constant. This can occur when a div and rem of the same constant are used in the same basic block. it will be hoisted, but not leave the block.

Longer term we probably need to look into the X86 immediate cost model used by constant hoisting and maybe not mark div/rem immediates for hoisting at all.

This fixes the case from PR38649.

Differential Revision: https://reviews.llvm.org/D51000
------------------------------------------------------------------------

llvm-svn: 340359
2018-08-21 23:07:11 +00:00
Hans Wennborg
09ca0cddec Merging r339674:
------------------------------------------------------------------------
r339674 | aemerson | 2018-08-14 14:04:25 +0200 (Tue, 14 Aug 2018) | 3 lines

[GlobalISel][IRTranslator] Fix a bug in handling repeating struct types during argument lowering.

Differential Revision: https://reviews.llvm.org/D49442
------------------------------------------------------------------------

llvm-svn: 340358
2018-08-21 23:02:55 +00:00
Hans Wennborg
9fa66d83d5 Merging r340158:
------------------------------------------------------------------------
r340158 | s.desmalen | 2018-08-20 11:16:59 +0200 (Mon, 20 Aug 2018) | 16 lines

[AArch64][SVE] Asm: Add SVE System registers

This patch adds system registers for controlling aspects of SVE:
- ZCR_EL1  (r/w)   visible at EL1 and EL0.
- ZCR_EL2  (r/w)   visible at EL2 and Non-secure EL1 and EL0.
- ZCR_EL3  (r/w)   visible at all exception levels.

and a system register identifying SVE:
- ID_AA64ZFR0_EL1  (r)  SVE Feature identifier.

Reviewers: SjoerdMeijer, samparker, pbarrio, fhahn, javed.absar

Reviewed By: SjoerdMeijer

Differential Revision: https://reviews.llvm.org/D50885

------------------------------------------------------------------------

llvm-svn: 340355
2018-08-21 22:49:06 +00:00
Hans Wennborg
7a72546ff6 Merging r340181:
------------------------------------------------------------------------
r340181 | abataev | 2018-08-20 18:00:22 +0200 (Mon, 20 Aug 2018) | 7 lines

[OPENMP][BLOCKS]Fix PR38923: reference to a global variable is captured
by a block.

Added checks for capturing of the variable in the block when trying to
emit correct address for the variable with the reference type. This
extra check allows correctly identify the variables that are not
captured in the block context.
------------------------------------------------------------------------

llvm-svn: 340352
2018-08-21 22:41:40 +00:00
Hans Wennborg
d8568622e6 Merging r340191:
------------------------------------------------------------------------
r340191 | abataev | 2018-08-20 20:03:40 +0200 (Mon, 20 Aug 2018) | 6 lines

[OPENMP] Fix crash on the emission of the weak function declaration.

If the function is actually a weak reference, it should not be marked as
deferred definition as this is only a declaration. Patch adds checks for
the definitions if they must be emitted. Otherwise, only declaration is
emitted.
------------------------------------------------------------------------

llvm-svn: 340351
2018-08-21 22:39:17 +00:00
Hans Wennborg
e23b77ca93 Merging r339091:
------------------------------------------------------------------------
r339091 | stella.stamenova | 2018-08-07 06:08:46 +0200 (Tue, 07 Aug 2018) | 12 lines

[lit, tests] Fix failing lit test: shtest-format.py

Summary:
The problem here is that on windows double quotes are used for paths (usually) while single quotes are not. This is not generally a problem for the tests because the lit infrastructure tends to treat both the same. One (and possibly only) exception is when some tests are run in an external shell such as some of the shtest-format tests. In this case on windows the path to python was not created correctly because it had single quotes and the test failed.

This same test is already failing with python 3 which is why our testing missed the new failure. This patch will take care of the immediate failure with python 2 and I'll send a follow up for the python 3 failure.

Reviewers: asmith, zturner

Subscribers: delcypher, llvm-commits

Differential Revision: https://reviews.llvm.org/D50373
------------------------------------------------------------------------

llvm-svn: 340349
2018-08-21 22:34:54 +00:00
Hans Wennborg
9d0c8d3f87 Merging r339372, r339373, r339374, and r339379
------------------------------------------------------------------------
r339372 | steveire | 2018-08-09 22:05:03 +0200 (Thu, 09 Aug 2018) | 5 lines

Add getBeginLoc API to replace getLocStart

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D50346
------------------------------------------------------------------------

------------------------------------------------------------------------
r339373 | steveire | 2018-08-09 22:05:18 +0200 (Thu, 09 Aug 2018) | 7 lines

Add getBeginLoc API to replace getStartLoc

Reviewers: teemperor!

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D50347
------------------------------------------------------------------------

------------------------------------------------------------------------
r339374 | steveire | 2018-08-09 22:05:47 +0200 (Thu, 09 Aug 2018) | 5 lines

Add getEndLoc API to replace getLocEnd

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D50348
------------------------------------------------------------------------

------------------------------------------------------------------------
r339379 | steveire | 2018-08-09 22:21:09 +0200 (Thu, 09 Aug 2018) | 1 line

Fix build
------------------------------------------------------------------------

llvm-svn: 340332
2018-08-21 20:22:01 +00:00
Hans Wennborg
5396514e13 Merging r339895 and r339896:
------------------------------------------------------------------------
r339895 | niravd | 2018-08-16 18:31:14 +0200 (Thu, 16 Aug 2018) | 13 lines

[MC][X86] Enhance X86 Register expression handling to more closely match GCC.

Allow the comparison of x86 registers in the evaluation of assembler
directives. This generalizes and simplifies the extension from r334022
to catch another case found in the Linux kernel.

Reviewers: rnk, void

Reviewed By: rnk

Subscribers: hiraditya, nickdesaulniers, llvm-commits

Differential Revision: https://reviews.llvm.org/D50795
------------------------------------------------------------------------

------------------------------------------------------------------------
r339896 | d0k | 2018-08-16 18:50:23 +0200 (Thu, 16 Aug 2018) | 1 line

[MC] Remove unused variable
------------------------------------------------------------------------

llvm-svn: 340329
2018-08-21 19:58:00 +00:00
Hans Wennborg
e71890b66d Merging r339822:
------------------------------------------------------------------------
r339822 | carrot | 2018-08-16 00:08:26 +0200 (Thu, 16 Aug 2018) | 12 lines


[CodeGenPrepare] Add BothExtension type to PromotedInsts

This patch fixes PR38125.

Instruction extension types are recorded in PromotedInsts, it can be used later in function canGetThrough. If an instruction has two users with different extension types, it will be inserted into PromotedInsts two times in function promoteOperandForOther. The second one overwrites the first one, and the final extension type is wrong, later causes problem in canGetThrough.

This patch changes the simple bool extension type to 2-bit enum type, add a BothExtension type in addition to zero/sign extension. When an user sees BothExtension for an instruction, it actually knows nothing about how that instruction is extended.

Differential Revision: https://reviews.llvm.org/D49512


------------------------------------------------------------------------

llvm-svn: 340294
2018-08-21 16:15:59 +00:00
Hans Wennborg
72bbf8c531 Merging r340048:
------------------------------------------------------------------------
r340048 | nico | 2018-08-17 19:19:06 +0200 (Fri, 17 Aug 2018) | 10 lines

Make __shiftleft128 / __shiftright128 real compiler built-ins.

r337619 added __shiftleft128 / __shiftright128 as functions in intrin.h.
Microsoft's STL plans on using these functions, and they're using intrin0.h
which just has declarations of built-ins to not pull in the huge intrin.h
header in the standard library headers. That requires that these functions are
real built-ins.

https://reviews.llvm.org/D50907

------------------------------------------------------------------------

llvm-svn: 340289
2018-08-21 15:56:49 +00:00
Reid Kleckner
8a2eba80a7 Merging r340101:
------------------------------------------------------------------------
r340101 | rnk | 2018-08-17 15:11:31 -0700 (Fri, 17 Aug 2018) | 14 lines

Don't warn on returning the address of a label from a statement expression

Summary:
There isn't anything inherently wrong with returning a label from a
statement expression. In practice, the Linux kernel uses this pattern to
materialize PCs.

Fixes PR38569

Reviewers: niravd, rsmith, nickdesaulniers

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D50805
------------------------------------------------------------------------

llvm-svn: 340103
2018-08-17 22:18:56 +00:00
Reid Kleckner
786ae53d2b Merging r340079:
------------------------------------------------------------------------
r340079 | rnk | 2018-08-17 13:59:27 -0700 (Fri, 17 Aug 2018) | 20 lines

[MS] Mangle a hash of the main file path into anonymous namespaces

Summary:
This is needed to avoid conflicts in mangled names for codeview types in
anonymous namespaces. In CodeView, types refer to each other typically
through forward declarations, which contain mangled names. These names
have to be unique, otherwise the debugger will look up the mangled name
and find the wrong definition.

Furthermore, ThinLTO will deduplicate the types, and debug info
verification can fail when the types have the wrong sizes. This is
PR38608.

Fixes PR38609.

Reviewers: majnemer, inglorion, hans

Subscribers: mehdi_amini, aprantl, JDevlieghere, dexonsmith, cfe-commits

Differential Revision: https://reviews.llvm.org/D50877
------------------------------------------------------------------------

llvm-svn: 340087
2018-08-17 21:25:51 +00:00
Hans Wennborg
3fd44a109d Merging r338841:
------------------------------------------------------------------------
r338841 | jmorse | 2018-08-03 12:13:35 +0200 (Fri, 03 Aug 2018) | 11 lines

[Windows FS] Allow moving files in TempFile::keep

In r338216 / D49860 TempFile::keep was extended to allow keeping across
filesystems. The aim on Windows was to have this happen in rename_internal
using the existing system API. However, to fix an issue and preserve the
idea of "renaming" not being a move, put Windows keep-across-filesystem in
TempFile::keep.

Differential Revision: https://reviews.llvm.org/D50048


------------------------------------------------------------------------

llvm-svn: 340030
2018-08-17 14:28:33 +00:00
Hans Wennborg
54989e78e4 Merging r339945:
------------------------------------------------------------------------
r339945 | ctopper | 2018-08-16 23:54:02 +0200 (Thu, 16 Aug 2018) | 9 lines

[X86] In EFLAGS copy pass, don't emit EXTRACT_SUBREG instructions since we're after peephole

Normally the peephole pass converts EXTRACT_SUBREG to COPY instructions. But we're after peephole so we can't rely on it to clean these up.

To fix this, the eflags pass now emits a COPY with a subreg input.

I also noticed that in 32-bit mode we need to constrain the input to the copy to ensure the subreg is valid. Otherwise we'll fail verify-machineinstrs

Differential Revision: https://reviews.llvm.org/D50656
------------------------------------------------------------------------

llvm-svn: 339999
2018-08-17 07:38:52 +00:00
Hans Wennborg
7cea4193d9 Backport r339704 to 7.0 for PR38598
> Author: abataev
> Date: Tue Aug 14 11:31:20 2018
> New Revision: 339704
>
> URL: http://llvm.org/viewvc/llvm-project?rev=339704&view=rev
> Log:
> [OPENMP] Fix processing of declare target construct.
>
> The attribute marked as inheritable since OpenMP 5.0 supports it +
> additional fixes to support new functionality.

llvm-svn: 339998
2018-08-17 07:34:53 +00:00
Hans Wennborg
b90baad8a3 Merging r339883:
------------------------------------------------------------------------
r339883 | hans | 2018-08-16 17:12:12 +0200 (Thu, 16 Aug 2018) | 10 lines

[cmake] Prevent LLVMgold.so from being unloaded on Linux

Extend the fix from D40459 to also apply to modules such as the LLVM
gold plugin. This is needed because current binutils master (and future
binutils 2.32) calls dlclose() on bfd plugins as part of a recent fix
for https://sourceware.org/bugzilla/show_bug.cgi?id=23460.

Patch by Evangelos Foutras!

Differential Revision: https://reviews.llvm.org/D50416
------------------------------------------------------------------------

llvm-svn: 339993
2018-08-17 07:25:54 +00:00
Hans Wennborg
42db5f37f1 Merging r339816:
------------------------------------------------------------------------
r339816 | marshall | 2018-08-15 23:19:08 +0200 (Wed, 15 Aug 2018) | 1 line

Selectively import timespec_get into namespace std, since some C libraries don't have it. Reviewed as https://reviews.llvm.org/D50799
------------------------------------------------------------------------

llvm-svn: 339992
2018-08-17 07:22:08 +00:00
Hans Wennborg
ad568e4f19 Merging r339804:
------------------------------------------------------------------------
r339804 | marshall | 2018-08-15 21:27:53 +0200 (Wed, 15 Aug 2018) | 1 line

Mark the at_exit and at_quick_exit tests as unsupported under C++98 an 03, since those calls were introduced in C++11.  They're already guarded by an ifdef in the code, so this is a 'belt-and-suspenders' change.
------------------------------------------------------------------------

llvm-svn: 339991
2018-08-17 07:21:26 +00:00
Hans Wennborg
96148317d3 Merging r339742:
------------------------------------------------------------------------
r339742 | ldionne | 2018-08-15 02:18:01 +0200 (Wed, 15 Aug 2018) | 11 lines

[libc++] Disable failing C11 feature tests for <cfloat> and <float.h>

Summary:
Those tests are breaking the test bots. A Bugzilla has been filed to
make sure those tests are re-enabled: https://bugs.llvm.org/show_bug.cgi?id=38572

Reviewers: mclow.lists, EricWF

Subscribers: krytarowski, christof, dexonsmith, cfe-commits

Differential Revision: https://reviews.llvm.org/D50748
------------------------------------------------------------------------

llvm-svn: 339990
2018-08-17 07:20:52 +00:00
Hans Wennborg
c558aeea0c Merging r339741:
------------------------------------------------------------------------
r339741 | ldionne | 2018-08-15 02:16:41 +0200 (Wed, 15 Aug 2018) | 12 lines

[libc++] Detect C11 features on non-Clang compilers

Summary:
The macros were inside `#if defined(_LIBCPP_COMPILER_CLANG)`, which means
we would never detect C11 features on non-Clang compilers. According to
Marshall Clow, this is not the intended behavior.

Reviewers: mclow.lists, EricWF

Subscribers: krytarowski, christof, dexonsmith, cfe-commits

Differential Revision: https://reviews.llvm.org/D50748
------------------------------------------------------------------------

llvm-svn: 339989
2018-08-17 07:20:30 +00:00
Hans Wennborg
ff0e60f323 Merging r339702:
------------------------------------------------------------------------
r339702 | ldionne | 2018-08-14 20:16:56 +0200 (Tue, 14 Aug 2018) | 11 lines

[libc++] Fix incorrect definition of TEST_HAS_C11_FEATURES

Summary:
The macro was not defined in C++11 mode when it should have been, at least
according to how _LIBCPP_HAS_C11_FEATURES is defined.

Reviewers: mclow.lists, EricWF, jfb, dexonsmith

Subscribers: christof, dexonsmith, cfe-commits

Differential Revision: https://reviews.llvm.org/D50719
------------------------------------------------------------------------

llvm-svn: 339988
2018-08-17 07:20:04 +00:00
Hans Wennborg
719997b080 Merging r339675:
------------------------------------------------------------------------
r339675 | ldionne | 2018-08-14 15:29:17 +0200 (Tue, 14 Aug 2018) | 15 lines

[libc++] Add missing #include in C11 features tests

Summary:
These #includes are quite important, since otherwise any

    #if TEST_STD_VER > 14 && defined(TEST_HAS_C11_FEATURES)

checks are always false, and so we don't actually test for C11 support
in the standard library.

Reviewers: mclow.lists, EricWF

Subscribers: christof, dexonsmith, cfe-commits

Differential Revision: https://reviews.llvm.org/D50674
------------------------------------------------------------------------

llvm-svn: 339987
2018-08-17 07:19:32 +00:00
Hans Wennborg
ea525abfcb Merging r339904:
------------------------------------------------------------------------
r339904 | maskray | 2018-08-16 19:22:02 +0200 (Thu, 16 Aug 2018) | 11 lines

[ELF] mergeSections: remove non-alive MergeInputSection

Summary: This makes it conform to what the comment says. Otherwise when getErrPlace() is called afterwards, cast<InputSection>(D) will cause incompatible cast as MergeInputSection is not a subclass of InputSection.

Reviewers: ruiu, grimar, espindola, pcc

Reviewed By: grimar

Subscribers: emaste, arichardson, llvm-commits

Differential Revision: https://reviews.llvm.org/D50742
------------------------------------------------------------------------

llvm-svn: 339986
2018-08-17 07:08:25 +00:00
Hans Wennborg
25fb1ca68e Merging r339515:
------------------------------------------------------------------------
r339515 | d0k | 2018-08-12 13:43:03 +0200 (Sun, 12 Aug 2018) | 4 lines

[InstSimplify] Guard against large shift amounts.

These are always UB, but can happen for large integer inputs. Testing it
is very fragile as -simplifycfg will nuke the UB top-down.
------------------------------------------------------------------------

llvm-svn: 339985
2018-08-17 07:04:47 +00:00
Hans Wennborg
099600fc8b Merging r339874:
------------------------------------------------------------------------
r339874 | ldionne | 2018-08-16 14:44:28 +0200 (Thu, 16 Aug 2018) | 25 lines

[libcxx] By default, do not use internal_linkage to hide symbols from the ABI

Summary:
https://reviews.llvm.org/D49240 led to symbol size problems in Chromium, and
we expect this may be the case in other projects built in debug mode too.
Instead, unless users explicitly ask for internal_linkage, we use always_inline
like we used to.

In the future, when we have a solution that allows us to drop always_inline
without falling back on internal_linkage, we can replace always_inline by
that.

Note that this commit introduces a change in contract for existing libc++
users: by default, libc++ used to guarantee that TUs built with different
versions of libc++ could be linked together. With the introduction of the
_LIBCPP_HIDE_FROM_ABI_PER_TU macro, the default behavior is that TUs built
with different libc++ versions are not guaranteed to link. This is a change
in contract but not a change in behavior, since the current implementation
still allows linking TUs built with different libc++ versions together.

Reviewers: EricWF, mclow.lists, dexonsmith, hans, rnk

Subscribers: christof, cfe-commits

Differential Revision: https://reviews.llvm.org/D50652
------------------------------------------------------------------------

llvm-svn: 339882
2018-08-16 14:54:37 +00:00
Hans Wennborg
ada3e3cdb3 Merging r339865:
------------------------------------------------------------------------
r339865 | yroux | 2018-08-16 13:38:09 +0200 (Thu, 16 Aug 2018) | 7 lines

[libcxxabi] Fix test_exception_address_alignment test for ARM

Check _LIBCXXABI_ARM_EHABI macro instead of libunwind version.

Fixes PR34182

Differential revision: https://reviews.llvm.org/D50170
------------------------------------------------------------------------

llvm-svn: 339881
2018-08-16 14:49:38 +00:00
Hans Wennborg
4f88bfa0ee Merging r339769:
------------------------------------------------------------------------
r339769 | nemanjai | 2018-08-15 14:58:13 +0200 (Wed, 15 Aug 2018) | 12 lines

[PowerPC] Don't run BV DAG Combine before legalization if it assumes legal types

When trying to combine a DAG that builds a vector out of sign-extensions of
vector extracts, the code assumes legal input types. Due to that, we have to
disable this combine prior to legalization.
In some cases, the DAG will look slightly different after legalization so
account for that in the matching code.

This is a fix for https://bugs.llvm.org/show_bug.cgi?id=38087

Differential Revision: https://reviews.llvm.org/D49080

------------------------------------------------------------------------

llvm-svn: 339859
2018-08-16 10:13:29 +00:00
Hans Wennborg
e4f6c94bd7 Merging r339536:
------------------------------------------------------------------------
r339536 | ctopper | 2018-08-13 08:53:49 +0200 (Mon, 13 Aug 2018) | 3 lines

[SelectionDAG] In PromoteFloatOp_BITCAST, insert a bitcast after the fp_to_fp16 in case the result type isn't a scalar integer.

This is another variation of PR38533. In this case, the result type of the bitcast is legal and 16-bits wide, but not a scalar integer. So we need to emit the convert to i16 and then bitcast it to the true result type. This new bitcast will be further type legalized if necessary.
------------------------------------------------------------------------

llvm-svn: 339857
2018-08-16 10:02:47 +00:00
Hans Wennborg
f273c33c1f Merging r339535:
------------------------------------------------------------------------
r339535 | ctopper | 2018-08-13 08:53:47 +0200 (Mon, 13 Aug 2018) | 5 lines

[SelectionDAG] In PromoteIntRes_BITCAST, when the input is TypePromoteFloat, make sure the output type is scalar. For vectors, use a store and load of temporary.

Previously if the result type was a vector, we emitted a FP_TO_FP16 with a vector result type which isn't valid.

This is basically the opposite case of the root cause of PR38533.
------------------------------------------------------------------------

llvm-svn: 339856
2018-08-16 10:00:54 +00:00
Hans Wennborg
7b0a6d3246 Merging r339533:
------------------------------------------------------------------------
r339533 | ctopper | 2018-08-13 07:26:49 +0200 (Mon, 13 Aug 2018) | 5 lines

[SelectionDAG] In PromoteFloatRes_BITCAST, insert a bitcast before the fp16_to_fp in case the input type isn't an i16.

The bitcast can be further legalized as needed.

Fixes PR38533.
------------------------------------------------------------------------

llvm-svn: 339855
2018-08-16 09:58:56 +00:00
Hans Wennborg
9dc31a87e7 Merging r339743:
------------------------------------------------------------------------
r339743 | ldionne | 2018-08-15 02:30:03 +0200 (Wed, 15 Aug 2018) | 14 lines

[libcxx] Fix XFAILs for aligned allocation tests on older OSX versions

Summary:
Since r338934, Clang emits an error when aligned allocation functions are
used in conjunction with a system libc++ dylib that does not support those
functions. This causes some tests to fail when testing against older libc++
dylibs. This commit marks those tests as UNSUPPORTED, and also documents the
various reasons for the tests being unsupported.

Reviewers: vsapsai, EricWF

Subscribers: christof, dexonsmith, cfe-commits, mclow.lists, EricWF

Differential Revision: https://reviews.llvm.org/D50341
------------------------------------------------------------------------

llvm-svn: 339854
2018-08-16 09:52:16 +00:00
Hans Wennborg
8d3b6bcdbf Merging r339166:
------------------------------------------------------------------------
r339166 | abataev | 2018-08-07 21:21:05 +0200 (Tue, 07 Aug 2018) | 12 lines

[SLP] Fix insert point for reused extract instructions.

Summary:
Reworked the previously committed patch to insert shuffles for reused
extract element instructions in the correct position. Previous logic was
incorrect, and might lead to the crash with PHIs and EH instructions.

Reviewers: efriedma, javed.absar

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D50143
------------------------------------------------------------------------

llvm-svn: 339853
2018-08-16 09:48:15 +00:00
Hans Wennborg
b2177de8ba Merging r339794:
------------------------------------------------------------------------
r339794 | dim | 2018-08-15 19:30:32 +0200 (Wed, 15 Aug 2018) | 8 lines

For FreeBSD, don't define _M in nasty_macros.hpp

Because FreeBSD uses _M in its <sys/types.h>, and it is hard to avoid
including that header, only define _M to NASTY_MACRO for other operating
systems.  This fixes almost 2000 unexpected test failures.

Discussed with Eric Fiselier.

------------------------------------------------------------------------

llvm-svn: 339852
2018-08-16 09:45:10 +00:00
Hans Wennborg
5dfcfbf90c Merging r339603:
------------------------------------------------------------------------
r339603 | abataev | 2018-08-13 21:04:24 +0200 (Mon, 13 Aug 2018) | 4 lines

[OPENMP] Fix emission of the loop doacross constructs.

The number of loops associated with the OpenMP loop constructs should
not be considered as the number loops to collapse.
------------------------------------------------------------------------

llvm-svn: 339851
2018-08-16 09:35:01 +00:00
Hans Wennborg
db1dc2ea56 Merging r339697:
------------------------------------------------------------------------
r339697 | mstorsjo | 2018-08-14 19:33:10 +0200 (Tue, 14 Aug 2018) | 8 lines

[CMake] Fix the LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY option

This option should be available if LIBCXX_ENABLE_SHARED is enabled,
not LIBCXX_ENABLE_STATIC.

This fixes a typo from SVN r337814.

Differential Revision: https://reviews.llvm.org/D50691
------------------------------------------------------------------------

llvm-svn: 339850
2018-08-16 09:03:32 +00:00
Krzysztof Parzyszek
20089ece79 [ReleaseNotes] Fix a typo
llvm-svn: 339718
2018-08-14 19:42:19 +00:00
Krzysztof Parzyszek
4b14e145d4 [ReleaseNotes] Add release notes for Hexagon
llvm-svn: 339717
2018-08-14 19:40:56 +00:00
Reid Kleckner
a7a21e64cb Merging r339636:
------------------------------------------------------------------------
r339636 | rnk | 2018-08-13 18:24:35 -0700 (Mon, 13 Aug 2018) | 17 lines

[BasicAA] Don't assume tail calls with byval don't alias allocas

Summary:
Calls marked 'tail' cannot read or write allocas from the current frame
because the current frame might be destroyed by the time they run.
However, a tail call may use an alloca with byval. Calling with byval
copies the contents of the alloca into argument registers or stack
slots, so there is no lifetime issue. Tail calls never modify allocas,
so we can return just ModRefInfo::Ref.

Fixes PR38466, a longstanding bug.

Reviewers: hfinkel, nlewycky, gbiv, george.burgess.iv

Subscribers: hiraditya, llvm-commits

Differential Revision: https://reviews.llvm.org/D50679
------------------------------------------------------------------------

llvm-svn: 339698
2018-08-14 17:35:35 +00:00
Hans Wennborg
599b2d122f Merging r339600:
------------------------------------------------------------------------
r339600 | scott.linder | 2018-08-13 20:44:21 +0200 (Mon, 13 Aug 2018) | 8 lines

[CodeGen] Fix assert in SelectionDAG::computeKnownBits

Fix SelectionDAG::computeKnownBits asserting when handling EXTRACT_SUBVECTOR
when zero extending the demanded elements mask if it is already as long as the
source vector.

Differential Revision: https://reviews.llvm.org/D49574

------------------------------------------------------------------------

llvm-svn: 339664
2018-08-14 09:30:11 +00:00
Hans Wennborg
f3f6ca7957 Merging r339597:
------------------------------------------------------------------------
r339597 | erichkeane | 2018-08-13 20:33:20 +0200 (Mon, 13 Aug 2018) | 7 lines

Enforce instantiation of template multiversion functions

Multiversioned member functions inside of a template type were 
not properly being emitted.  The solution to this is to simply 
ensure that their bodies are correctly evaluated/assigned during
template instantiation.

------------------------------------------------------------------------

llvm-svn: 339663
2018-08-14 09:20:55 +00:00
Hans Wennborg
7b0c6a2c02 Merging r339431:
------------------------------------------------------------------------
r339431 | ldionne | 2018-08-10 15:24:56 +0200 (Fri, 10 Aug 2018) | 16 lines

[libc++] Enable aligned allocation based on feature test macro, irrespective of standard

Summary:
The current code enables aligned allocation functions when compiling in C++17
and later. This is a problem because aligned allocation functions might not
be supported on the target platform, which leads to an error at link time.

Since r338934, Clang knows not to define __cpp_aligned_new when it's not
available on the target platform -- this commit takes advantage of that to
only use aligned allocation functions when they are available.

Reviewers: vsapsai, EricWF

Subscribers: christof, dexonsmith, cfe-commits, EricWF, mclow.lists

Differential Revision: https://reviews.llvm.org/D50344
------------------------------------------------------------------------

llvm-svn: 339661
2018-08-14 09:13:39 +00:00
Hans Wennborg
8a6427840e Merging r338934:
------------------------------------------------------------------------
r338934 | vsapsai | 2018-08-04 01:12:37 +0200 (Sat, 04 Aug 2018) | 29 lines

[Preprocessor] Allow libc++ to detect when aligned allocation is unavailable.

Libc++ needs to know when aligned allocation is supported by clang, but is
otherwise unavailable at link time. Otherwise, libc++ will incorrectly end up
generating calls to `__builtin_operator_new`/`__builtin_operator_delete` with
alignment arguments.

This patch implements the following changes:

* The `__cpp_aligned_new` feature test macro to no longer be defined when
  aligned allocation is otherwise enabled but unavailable.

* The Darwin driver no longer passes `-faligned-alloc-unavailable` when the
  user manually specifies `-faligned-allocation` or `-fno-aligned-allocation`.

* Instead of a warning Clang now generates a hard error when an aligned
  allocation or deallocation function is referenced but unavailable.

Patch by Eric Fiselier.

Reviewers: rsmith, vsapsai, erik.pilkington, ahatanak, dexonsmith

Reviewed By: rsmith

Subscribers: Quuxplusone, cfe-commits

Differential Revision: https://reviews.llvm.org/D45015


------------------------------------------------------------------------

llvm-svn: 339660
2018-08-14 09:10:53 +00:00
Hans Wennborg
6141c26486 Merging r339049:
------------------------------------------------------------------------
r339049 | mstorsjo | 2018-08-06 21:49:18 +0200 (Mon, 06 Aug 2018) | 8 lines

[COFF] Remove a superfluous warning about aligncomm for non-common symbols

It's not an error if a common symbol (uninitialized data, with alignment
specified via the aligncomm directive) is replaced with a regular
one with initialized data (with alignment specified via the section
chunk).

Differential Revision: https://reviews.llvm.org/D50268
------------------------------------------------------------------------

llvm-svn: 339658
2018-08-14 08:59:56 +00:00
Hans Wennborg
9b38a730d1 Merging r339076:
------------------------------------------------------------------------
r339076 | stella.stamenova | 2018-08-07 00:37:53 +0200 (Tue, 07 Aug 2018) | 10 lines

[lit, python] Always add quotes around the python path in lit

Summary:
The issue with the python path is that the path to python on Windows can contain spaces. To make the tests always work, the path to python needs to be surrounded by quotes.

This is a companion change to: https://reviews.llvm.org/D50206

Reviewers: asmith, zturner

Differential Revision: https://reviews.llvm.org/D50280
------------------------------------------------------------------------

llvm-svn: 339657
2018-08-14 08:51:28 +00:00
Hans Wennborg
c662a52399 Merging r339075:
------------------------------------------------------------------------
r339075 | stella.stamenova | 2018-08-07 00:37:49 +0200 (Tue, 07 Aug 2018) | 12 lines

[lit, python] Always add quotes around the python path in lit

Summary:
The issue with the python path is that the path to python on Windows can contain spaces. To make the tests always work, the path to python needs to be surrounded by quotes.

This is a companion change to: https://reviews.llvm.org/D50206

Reviewers: asmith, zturner, espindola

Subscribers: emaste, sbc100, arichardson, aheejin, steven_wu, dexonsmith, llvm-commits

Differential Revision: https://reviews.llvm.org/D50282
------------------------------------------------------------------------

llvm-svn: 339656
2018-08-14 08:49:47 +00:00
Martin Storsjo
a5e23f0874 [ReleaseNotes] Mention noteworthy changes for 7.0
llvm-svn: 339648
2018-08-14 07:53:15 +00:00
Martin Storsjo
80a10ad9cb [ReleaseNotes] Mention one Windows specific change for 7.0
llvm-svn: 339647
2018-08-14 07:52:21 +00:00
Martin Storsjo
371f3503ef [ReleaseNotes] Mention various windows related changes in 7.0
llvm-svn: 339646
2018-08-14 07:48:10 +00:00
Hans Wennborg
e5c5c47b70 Merging r339264:
------------------------------------------------------------------------
r339264 | rksimon | 2018-08-08 17:53:14 +0200 (Wed, 08 Aug 2018) | 5 lines

[CGObjCGNU] Rename GetSelector helper method to fix -Woverloaded-virtual warning (PR38210)

As suggested by @theraven on PR38210, this patch fixes the gcc -Woverloaded-virtual warnings by renaming the extra CGObjCGNU::GetSelector method to CGObjCGNU::GetTypedSelector

Differential Revision: https://reviews.llvm.org/D50448
------------------------------------------------------------------------

llvm-svn: 339555
2018-08-13 11:53:27 +00:00
Hans Wennborg
e6a0875aed Merging r339074:
------------------------------------------------------------------------
r339074 | stella.stamenova | 2018-08-07 00:37:45 +0200 (Tue, 07 Aug 2018) | 12 lines

[lit, python] Always add quotes around the python path in lit

Summary:
The issue with the python path is that the path to python on Windows can contain spaces. To make the tests always work, the path to python needs to be surrounded by quotes.

This is a companion change to: https://reviews.llvm.org/D50206

Reviewers: asmith, zturner

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D50281
------------------------------------------------------------------------

llvm-svn: 339554
2018-08-13 11:51:39 +00:00
Hans Wennborg
9de4c4fece Merging r339411:
------------------------------------------------------------------------
r339411 | gbiv | 2018-08-10 07:14:43 +0200 (Fri, 10 Aug 2018) | 17 lines

[MemorySSA] "Fix" lifetime intrinsic handling

MemorySSA currently creates MemoryAccesses for lifetime intrinsics, and
sometimes treats them as clobbers. This may/may not be the best way
forward, but while we're doing it, we should consider
MayAlias/PartialAlias to be clobbers.

The ideal fix here is probably to remove all of this reasoning about
lifetimes from MemorySSA + put it into the passes that need to care. But
that's a wayyy broader fix that needs some consensus, and we have
miscompiles + a release branch today, and this should solve the
miscompiles just as well.

differential revision is D43269. Landing without an explicit LGTM (and
without using the special please-autoclose-this syntax) so we can still
use that revision as a place to decide what the right fix here is.

------------------------------------------------------------------------

llvm-svn: 339545
2018-08-13 08:28:30 +00:00
Hans Wennborg
43d7c7dff0 Merging r339492:
------------------------------------------------------------------------
r339492 | tstellar | 2018-08-11 03:08:34 +0200 (Sat, 11 Aug 2018) | 9 lines

[gold] Fix Tests cases on i686

Reviewers: tejohnson

Reviewed By: tejohnson

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D50583
------------------------------------------------------------------------

llvm-svn: 339544
2018-08-13 08:25:39 +00:00
Hans Wennborg
3a3b7af45d Merging r339179 and r339184:
------------------------------------------------------------------------
r339179 | stella.stamenova | 2018-08-07 22:54:38 +0200 (Tue, 07 Aug 2018) | 12 lines

[lit, python3] Update lit error logging to work correctly in python3 and other test fixes

Summary:
In Python2 'unicode' is a distinct type from 'str', but in Python3 'unicode' does not exist and instead all 'str' objects are Unicode string. This change updates the logic in the test logging for lit to correctly process each of the types, and more importantly, to not just fail in Python3.

This change also reverses the use of quotes in several of the cfg files. By using '""' we are guaranteeing that the resulting path will work correctly on Windows while "''" only works correctly sometimes. This also fixes one of the failing tests.

Reviewers: asmith, zturner

Subscribers: stella.stamenova, delcypher, llvm-commits

Differential Revision: https://reviews.llvm.org/D50397
------------------------------------------------------------------------

------------------------------------------------------------------------
r339184 | stella.stamenova | 2018-08-07 23:21:30 +0200 (Tue, 07 Aug 2018) | 3 lines

[lit] Disable shtest-timeout on Windows

This test passes on Windows when using Python 3 but fails when using Python 2, so it needs more investigation before it can be enabled as the bots use Python 2.
------------------------------------------------------------------------

llvm-svn: 339542
2018-08-13 08:15:58 +00:00
Hans Wennborg
85a67580c5 Merging r339073:
------------------------------------------------------------------------
r339073 | stella.stamenova | 2018-08-07 00:37:44 +0200 (Tue, 07 Aug 2018) | 14 lines

[lit, python] Always add quotes around the python path in lit

Summary:
The issue with the python path is that the path to python on Windows can contain spaces. To make the tests always work, the path to python needs to be surrounded by quotes.

This change updates several configuration files which specify the path to python as a substitution and also remove quotes from existing tests.

Reviewers: asmith, zturner, alexshap, jakehehrlich

Reviewed By: zturner, alexshap, jakehehrlich

Subscribers: mehdi_amini, nemanjai, eraman, kbarton, jakehehrlich, steven_wu, dexonsmith, stella.stamenova, delcypher, llvm-commits

Differential Revision: https://reviews.llvm.org/D50206
------------------------------------------------------------------------

llvm-svn: 339541
2018-08-13 08:13:43 +00:00
Hans Wennborg
de814ae681 Merging r339225:
------------------------------------------------------------------------
r339225 | thopre | 2018-08-08 11:35:26 +0200 (Wed, 08 Aug 2018) | 11 lines

Support inline asm with multiple 64bit output in 32bit GPR

Summary: Extend fix for PR34170 to support inline assembly with multiple output operands that do not naturally go in the register class it is constrained to (eg. double in a 32-bit GPR as in the PR).

Reviewers: bogner, t.p.northover, lattner, javed.absar, efriedma

Reviewed By: efriedma

Subscribers: efriedma, tra, eraman, javed.absar, llvm-commits

Differential Revision: https://reviews.llvm.org/D45437
------------------------------------------------------------------------

llvm-svn: 339539
2018-08-13 08:03:40 +00:00
Hans Wennborg
6757207d9a Merging r339428 and r339494:
------------------------------------------------------------------------
r339428 | theraven | 2018-08-10 14:53:13 +0200 (Fri, 10 Aug 2018) | 18 lines

Add Windows support for the GNUstep Objective-C ABI V2.

Summary:
Introduces funclet-based unwinding for Objective-C and fixes an issue
where global blocks can't have their isa pointers initialised on
Windows.

After discussion with Dustin, this changes the name mangling of
Objective-C types to prevent a C++ catch statement of type struct X*
from catching an Objective-C object of type X*.

Reviewers: rjmccall, DHowett-MSFT

Reviewed By: rjmccall, DHowett-MSFT

Subscribers: mgrang, mstorsjo, smeenai, cfe-commits

Differential Revision: https://reviews.llvm.org/D50144
------------------------------------------------------------------------

------------------------------------------------------------------------
r339494 | dyung | 2018-08-11 04:46:47 +0200 (Sat, 11 Aug 2018) | 2 lines

Make the section boundary checks on Windows not depend on the order as they are emitted in reverse when the compiler is built by Visual C++.

------------------------------------------------------------------------

llvm-svn: 339538
2018-08-13 07:59:11 +00:00
Ulrich Weigand
51c9fed89d [7.0 branch] Update release notes (SystemZ, TableGen)
This updates the 7.0 branch release notes to mention the SystemZ
specific changes, and also the new support for multi-alternative
patterns in TableGen (see D48545).

Reviewed by: hans
Differential Revision: https://reviews.llvm.org/D50514

llvm-svn: 339355
2018-08-09 16:18:00 +00:00
Hans Wennborg
ace5c2356a Merging r339281:
------------------------------------------------------------------------
r339281 | ctopper | 2018-08-08 21:14:23 +0200 (Wed, 08 Aug 2018) | 5 lines

[CodeGen][Timers] Enable llvm::TimePassesIsEnabled when -ftime-report is specified

r330571 added a new FrontendTimesIsEnabled variable and replaced many usages of llvm::TimePassesIsEnabled. Including the place that set llvm::TimePassesIsEnabled for -ftime-report. The effect of this is that -ftime-report now only contains the timers specifically referenced in CodeGenAction.cpp and none of the timers in the backend.

This commit adds back the assignment, but otherwise leaves everything else unchanged.
------------------------------------------------------------------------

llvm-svn: 339341
2018-08-09 12:46:44 +00:00
Hans Wennborg
4d989f7996 Merging r339317:
------------------------------------------------------------------------
r339317 | theraven | 2018-08-09 10:02:42 +0200 (Thu, 09 Aug 2018) | 15 lines

Correctly initialise global blocks on Windows.

Summary:
Windows does not allow globals to be initialised to point to globals in
another DLL.  Exported globals may be referenced only from code.  Work
around this by creating an initialiser that runs in early library
initialisation and sets the isa pointer.

Reviewers: rjmccall

Reviewed By: rjmccall

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D50436
------------------------------------------------------------------------

llvm-svn: 339339
2018-08-09 12:42:36 +00:00
Hans Wennborg
850d801d57 Merging r339316:
------------------------------------------------------------------------
r339316 | hahnfeld | 2018-08-09 09:45:49 +0200 (Thu, 09 Aug 2018) | 16 lines

[NVPTX] Select atomic loads and stores

According to PTX ISA .volatile has the same memory synchronization
semantics as .relaxed.sys, so it can be used to implement monotonic
atomic loads and stores. This is important for OpenMP's atomic
construct where
 - 'read's and 'write's are lowered to atomic loads and stores, and
 - an update of float or double types are lowered into a cmpxchg loop.
(Note that PTX could do better because it has atom.add.f{32,64} but
LLVM's atomicrmw instruction only allows integer types.)

Higher levels of atomicity (like acquire and release) need additional
synchronization properties which were added with PTX ISA 6.0 / sm_70.
So using these instructions still results in an error.

Differential Revision: https://reviews.llvm.org/D50391
------------------------------------------------------------------------

llvm-svn: 339338
2018-08-09 12:37:40 +00:00
Hans Wennborg
f57a2d5bf8 Merging r339319:
------------------------------------------------------------------------
r339319 | hans | 2018-08-09 10:41:03 +0200 (Thu, 09 Aug 2018) | 1 line

cmake: don't pack system libs unless CMAKE_INSTALL_UCRT_LIBRARIES is set (PR38476)
------------------------------------------------------------------------

llvm-svn: 339323
2018-08-09 09:35:38 +00:00
Hans Wennborg
8389196dd9 Merging r339303:
------------------------------------------------------------------------
r339303 | george.karpenkov | 2018-08-09 02:41:22 +0200 (Thu, 09 Aug 2018) | 11 lines

[libFuzzer] Increase the iteration limit in shrink.test

After https://reviews.llvm.org/D48800, shrink.test started failing on
x86_64h architecture.
Looking into this, the optimization pass is too eager to unroll the loop
on x86_64h, possibly leading to worse coverage data.

Alternative solutions include not unrolling the loop when fuzzing, or
disabling this test on that architecture.

Differential Revision: https://reviews.llvm.org/D50484
------------------------------------------------------------------------

llvm-svn: 339315
2018-08-09 07:32:30 +00:00
Hans Wennborg
9f482deaa3 Merging r338902:
------------------------------------------------------------------------
r338902 | jgalenson | 2018-08-03 19:12:23 +0200 (Fri, 03 Aug 2018) | 5 lines

Fix crash in bounds checking.

In r337830 I added SCEV checks to enable us to insert fewer bounds checks.  Unfortunately, this sometimes crashes when multiple bounds checks are added due to SCEV caching issues.  This patch splits the bounds checking pass into two phases, one that computes all the conditions (using SCEV checks) and the other that adds the new instructions.

Differential Revision: https://reviews.llvm.org/D49946
------------------------------------------------------------------------

llvm-svn: 339239
2018-08-08 13:14:57 +00:00
Hans Wennborg
8732f8f547 Merging r339210:
------------------------------------------------------------------------
r339210 | rsmith | 2018-08-08 02:42:42 +0200 (Wed, 08 Aug 2018) | 2 lines

PR38286: Don't crash when attempting to define a constructor for an
incomplete class template.
------------------------------------------------------------------------

llvm-svn: 339236
2018-08-08 12:06:21 +00:00
Hans Wennborg
466ccce944 Merging r339190:
------------------------------------------------------------------------
r339190 | jvesely | 2018-08-07 23:54:37 +0200 (Tue, 07 Aug 2018) | 12 lines

AMDGPU: Remove broken i16 ternary patterns

Fixup test to check for GCN prefix
These patterns always zero extend the result even though it might need sign extension.
This has been broken since the addition of i16 support.
It has popped up in mad_sat(char) test since min(max()) combination is turned into v_med3, resulting in the following (incorrect) sequence:
        v_mad_i16 v2, v10, v9, v11
        v_med3_i32 v2, v2, v8, v7

Fixes mad_sat(char) piglit on VI.

Differential Revision: https://reviews.llvm.org/D49836
------------------------------------------------------------------------

llvm-svn: 339235
2018-08-08 11:35:18 +00:00
Hans Wennborg
4eb9806913 Merging r338716:
------------------------------------------------------------------------
r338716 | spatel | 2018-08-02 15:46:20 +0200 (Thu, 02 Aug 2018) | 41 lines

[ValueTracking] fix maxnum miscompile for cannotBeOrderedLessThanZero (PR37776)

This adds the NAN checks suggested in PR37776:
https://bugs.llvm.org/show_bug.cgi?id=37776

If both operands to maxnum are NAN, that should get constant folded, so we don't 
have to handle that case. This is the same assumption as other FP ops in this
function. Returning 'false' is always conservatively correct.

Copying from the bug report:

Currently, we have this for "when is cannotBeOrderedLessThanZero 
(mustBePositiveOrNaN) true for maxnum":
               L
        -------------------
        | Pos | Neg | NaN |
   ------------------------
   |Pos |  x  |  x  |  x  |
   ------------------------
 R |Neg |  x  |     |  x  |
   ------------------------
   |NaN |  x  |  x  |  x  |
   ------------------------


The cases with (Neg & NaN) are wrong. We should have:

                L
        -------------------
        | Pos | Neg | NaN |
   ------------------------
   |Pos |  x  |  x  |  x  |
   ------------------------
 R |Neg |  x  |     |     |
   ------------------------
   |NaN |  x  |     |  x  |
   ------------------------

Differential Revision: https://reviews.llvm.org/D50081


------------------------------------------------------------------------

llvm-svn: 339234
2018-08-08 11:31:39 +00:00
Hans Wennborg
e5aaa0579f Merging r339128:
------------------------------------------------------------------------
r339128 | theraven | 2018-08-07 14:02:46 +0200 (Tue, 07 Aug 2018) | 8 lines

[objc-gnustep] Don't emit .guess ivar offset vars.

These were intended to allow non-fragile and fragile ABI code to be
mixed, as long as the fragile classes were higher up the hierarchy than
the non-fragile ones.  Unfortunately:

 - No one actually wants to do this.
 - Recent versions of Linux's run-time linker break it.
------------------------------------------------------------------------

llvm-svn: 339233
2018-08-08 11:27:49 +00:00
Hans Wennborg
a6a8a0dc0c Merging r339217:
------------------------------------------------------------------------
r339217 | cdavis | 2018-08-08 06:21:24 +0200 (Wed, 08 Aug 2018) | 11 lines

[libunwind] Fix pointer-to-integer cast warnings on LLP64.

Summary:
`long` is too short on LLP64. We have to use `intptr_t` to
avoid truncating pointers.

Reviewers: mstorsjo, rnk, compnerd, smeenai

Subscribers: christof, cfe-commits, llvm-commits

Differential Revision: https://reviews.llvm.org/D50412
------------------------------------------------------------------------

llvm-svn: 339222
2018-08-08 07:50:31 +00:00
Hans Wennborg
b6d96c3866 Merging r339170:
------------------------------------------------------------------------
r339170 | mstorsjo | 2018-08-07 22:02:40 +0200 (Tue, 07 Aug 2018) | 5 lines

[Headers] Expand _Unwind_Exception for SEH on MinGW/x86_64

This matches how GCC defines this struct.

Differential Revision: https://reviews.llvm.org/D50380
------------------------------------------------------------------------

llvm-svn: 339220
2018-08-08 06:37:32 +00:00
Hans Wennborg
dc65afcc36 ReleaseNotes: the new vs integration
llvm-svn: 339133
2018-08-07 12:27:25 +00:00
Hans Wennborg
1c21f5b429 Merging r339058:
------------------------------------------------------------------------
r339058 | mstorsjo | 2018-08-06 23:26:09 +0200 (Mon, 06 Aug 2018) | 16 lines

[COFF] Treat .xdata/.pdata$<sym> as implicitly associative to <sym> for MinGW

MinGW configurations don't use associative comdats, as GNU ld doesn't
support that. Instead they produce normal comdats named .text$sym,
.xdata$sym and .pdata$sym.

GNU ld doesn't discard any comdats starting with .xdata or .pdata,
even if --gc-sections is used (while it does discard other unreferenced
comdats), regardless of what symbol name is used after the $ separator.

For LLD, treat any such comdat as implicitly associative to the base
symbol. This requires maintaining a map from symbol name to section
number, but that is only maintained when the MinGW flag has been
enabled.

Differential Revision: https://reviews.llvm.org/D49700
------------------------------------------------------------------------

llvm-svn: 339108
2018-08-07 07:46:29 +00:00
Hans Wennborg
57c21c9592 Merging r338949:
------------------------------------------------------------------------
r338949 | lemo | 2018-08-04 04:15:26 +0200 (Sat, 04 Aug 2018) | 27 lines

Fix a bug in VMRange

I noticed a suspicious failure:

[ RUN ] VMRange.CollectionContains
llvm/src/tools/lldb/unittests/Utility/VMRangeTest.cpp:146: Failure
Value of: VMRange::ContainsRange(collection, VMRange(0x100, 0x104))

Actual: false
Expected: true

Looking at the code, it is a very real bug:

class RangeInRangeUnaryPredicate {
public:
  RangeInRangeUnaryPredicate(VMRange range) : _range(range) {} // note that _range binds to a temporary!
  bool operator()(const VMRange &range) const {
    return range.Contains(_range);
  }
  const VMRange &_range;
};

This change fixes the bug.

Differential Revision: https://reviews.llvm.org/D50290


------------------------------------------------------------------------

llvm-svn: 339107
2018-08-07 07:43:13 +00:00
Hans Wennborg
54bbd10d8d Merging r338915:
------------------------------------------------------------------------
r338915 | ctopper | 2018-08-03 22:14:18 +0200 (Fri, 03 Aug 2018) | 5 lines

[SelectionDAG] Teach LegalizeVectorTypes to widen the mask input to a masked store.

The mask operand is visited before the data operand so we need to be able to widen it.

Fixes PR38436.
------------------------------------------------------------------------

llvm-svn: 339106
2018-08-07 07:40:45 +00:00
Hans Wennborg
d9371841f6 Merging r338610:
------------------------------------------------------------------------
r338610 | jvesely | 2018-08-01 20:36:07 +0200 (Wed, 01 Aug 2018) | 3 lines

AMDGPU/R600: Convert kernel param loads to use PARAM_I_ADDRESS

Non ext aligned i32 loads are still optimized to use CONSTANT_BUFFER (AS 8)
------------------------------------------------------------------------

llvm-svn: 339105
2018-08-07 07:37:32 +00:00
Hans Wennborg
7f4ef00eb2 Merging r338569:
------------------------------------------------------------------------
r338569 | jvesely | 2018-08-01 17:04:36 +0200 (Wed, 01 Aug 2018) | 5 lines

AMDGPU: Allow fp32-denormals feature for r600 targets

This was accidentally removed in r335942.

Differential Revision: https://reviews.llvm.org/D49934
------------------------------------------------------------------------

llvm-svn: 339103
2018-08-07 07:01:41 +00:00
Hans Wennborg
cebee05a4d Merging r338627:
------------------------------------------------------------------------
r338627 | mgorny | 2018-08-01 22:38:22 +0200 (Wed, 01 Aug 2018) | 7 lines

[test] Fix %hmaptool path for standalone builds

Fix %hmaptool path to refer to clang_tools_dir instead of
llvm_tools_dir, in order to fix standalone builds.  The tool is built
as part of clang, so it won't be found in installed LLVM tools.

Differential Revision: https://reviews.llvm.org/D50156
------------------------------------------------------------------------

llvm-svn: 339102
2018-08-07 06:57:36 +00:00
Hans Wennborg
9228f08eb5 Merging r338968:
------------------------------------------------------------------------
r338968 | echristo | 2018-08-05 16:23:37 +0200 (Sun, 05 Aug 2018) | 6 lines

Revert "Add a warning if someone attempts to add extra section flags to sections"

There are a bunch of edge cases and inconsistencies in how we're emitting sections
cause this warning to fire and it needs more work.

This reverts commit r335558.
------------------------------------------------------------------------

llvm-svn: 339099
2018-08-07 06:25:54 +00:00
Hans Wennborg
76c03a515a Merging r338665:
------------------------------------------------------------------------
r338665 | lliu0 | 2018-08-02 03:54:12 +0200 (Thu, 02 Aug 2018) | 11 lines

Fix FCOPYSIGN expansion

In expansion of FCOPYSIGN, the shift node is missing when the two
operands of FCOPYSIGN are of the same size. We should always generate
shift node (if the required shift bit is not zero) to put the sign
bit into the right position, regardless of the size of underlying
types.

Differential Revision: https://reviews.llvm.org/D49973


------------------------------------------------------------------------

llvm-svn: 339098
2018-08-07 06:23:16 +00:00
Hans Wennborg
babd002ba8 Merging r338817:
------------------------------------------------------------------------
r338817 | inouehrs | 2018-08-03 07:39:48 +0200 (Fri, 03 Aug 2018) | 10 lines

[InstSimplify] fold extracting from std::pair (2/2)

This is the second patch of the series which intends to enable jump threading for an inlined method whose return type is std::pair<int, bool> or std::pair<bool, int>. 
The first patch is https://reviews.llvm.org/rL338485.

This patch handles code sequences that merges two values using `shl` and `or`, then extracts one value using `and`.

Differential Revision: https://reviews.llvm.org/D49981


------------------------------------------------------------------------

llvm-svn: 339097
2018-08-07 06:20:40 +00:00
Hans Wennborg
3f3701060b Merging r338942:
------------------------------------------------------------------------
r338942 | rsmith | 2018-08-04 03:02:00 +0200 (Sat, 04 Aug 2018) | 1 line

[www] Update cxx_status and cxx_dr_status now that Clang 7 has branched.
------------------------------------------------------------------------

llvm-svn: 339002
2018-08-06 10:32:02 +00:00
Hans Wennborg
c7a1b92d79 Merging r338679, r338684, r338697, r338699:
------------------------------------------------------------------------
r338679 | grimar | 2018-08-02 10:07:07 +0200 (Thu, 02 Aug 2018) | 10 lines

[LLD] - Improve handling of AT> linker script commands

Patch by Konstantin Schwarz!

The condition to create a new phdr must also check the usage of "AT>" 
linker script command, and create a new PT_LOAD header if a new LMARegion is used.

This fixes PR38307

Differential revision: https://reviews.llvm.org/D50052
------------------------------------------------------------------------

------------------------------------------------------------------------
r338684 | grimar | 2018-08-02 10:13:56 +0200 (Thu, 02 Aug 2018) | 9 lines

[LLD] Only increase LMARegion if different from MemRegion

Patch by Konstantin Schwarz!

If both the MemRegion and LMARegion are set for an output section in
a linker script, we should only increase the LMARegion if it is
different from the MemRegion. Otherwise, we reserve the memory twice.

Differential revision: https://reviews.llvm.org/D50065
------------------------------------------------------------------------

------------------------------------------------------------------------
r338697 | grimar | 2018-08-02 12:45:46 +0200 (Thu, 02 Aug 2018) | 9 lines

[LLD] Do not overwrite LMAOffset of PT_LOAD header

Patch by Konstantin Schwarz!

If more than a single output section is added to a PT_LOAD header,
only the first section should set the LMAOffset of the segment.
Otherwise, we get a load-address overlap error

Differential revision: https://reviews.llvm.org/D50133
------------------------------------------------------------------------

------------------------------------------------------------------------
r338699 | grimar | 2018-08-02 12:59:28 +0200 (Thu, 02 Aug 2018) | 5 lines

[LLD][ELF] - Simplify. NFC.

isHeaderSection can be useful I believe,
but probably not right now and not
for this case.
------------------------------------------------------------------------

llvm-svn: 339000
2018-08-06 10:15:52 +00:00
David Carlier
fefd94a85f Release notes for write exec detection features
llvm-svn: 338993
2018-08-06 08:05:11 +00:00
Paul Robinson
d08e938917 Release note for DWARF v5 support
llvm-svn: 338892
2018-08-03 14:05:11 +00:00
Paul Robinson
bbd95a6951 Release note for DWARF v5 support
llvm-svn: 338891
2018-08-03 14:04:59 +00:00
Hans Wennborg
69794107d9 Merging r338599:
------------------------------------------------------------------------
r338599 | vlad.tsyrklevich | 2018-08-01 19:44:37 +0200 (Wed, 01 Aug 2018) | 16 lines

[X86] FastISel fall back on !absolute_symbol GVs

Summary:
D25878, which added support for !absolute_symbol for normal X86 ISel,
did not add support for materializing references to absolute symbols for
X86 FastISel. This causes build failures because FastISel generates
PC-relative relocations for absolute symbols. Fall back to normal ISel
for references to !absolute_symbol GVs. Fix for PR38200.

Reviewers: pcc, craig.topper

Reviewed By: pcc

Subscribers: hiraditya, llvm-commits, kcc

Differential Revision: https://reviews.llvm.org/D50116
------------------------------------------------------------------------

llvm-svn: 338847
2018-08-03 10:26:56 +00:00
Hans Wennborg
6d8abb0718 Merging r338762:
------------------------------------------------------------------------
r338762 | gbiv | 2018-08-02 21:50:27 +0200 (Thu, 02 Aug 2018) | 15 lines

[Support] Add an enable bit to our DebugCounters

r337748 made us start incrementing DebugCounters all of the time. This
makes tsan unhappy in multithreaded environments.

Since it doesn't make much sense to use DebugCounters with multiple
threads, this patch makes us only count anything if the user passed a
-debug-counter option or if some other piece of code explicitly asks
for it (e.g. the pass in D50031).

The amount of global state here makes writing a unittest for this
behavior somewhat awkward. So, no test is provided.

Differential Revision: https://reviews.llvm.org/D50150

------------------------------------------------------------------------

llvm-svn: 338846
2018-08-03 10:23:43 +00:00
Hans Wennborg
91764583f2 Merging r338749:
------------------------------------------------------------------------
r338749 | mstorsjo | 2018-08-02 20:12:08 +0200 (Thu, 02 Aug 2018) | 6 lines

Work around more GCC miscompiles exposed by r338464.

This is the same fix as in r338478, for another occurrance of the
same pattern from r338464.

See gcc.gnu.org/PR86769 for details of the bug.
------------------------------------------------------------------------

llvm-svn: 338845
2018-08-03 10:20:21 +00:00
Hans Wennborg
8c6b6d1141 Merging r338757:
------------------------------------------------------------------------
r338757 | jlpeyton | 2018-08-02 21:13:07 +0200 (Thu, 02 Aug 2018) | 8 lines

[OpenMP] Fix doacross testing for gcc

This patch adds a test using the doacross clauses in OpenMP and removes gcc from
testing kmp_doacross_check.c which is only testing the kmp rather than the
gomp interface.

Differential Revision: https://reviews.llvm.org/D50014

------------------------------------------------------------------------

llvm-svn: 338844
2018-08-03 10:18:17 +00:00
Hans Wennborg
ceaf95f93d Merging r338751:
------------------------------------------------------------------------
r338751 | tstellar | 2018-08-02 20:16:10 +0200 (Thu, 02 Aug 2018) | 13 lines

CMake: Remove LLVM_DYLIB_SYMBOL_VERSIONING

Summary:
This option is no longer needed since r300496 added symbol
versioning by default

Reviewers: sylvestre.ledru, beanz, mgorny

Reviewed By: mgorny

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D49835
------------------------------------------------------------------------

llvm-svn: 338842
2018-08-03 10:15:36 +00:00
Hans Wennborg
23798fa3ae Merging r338703 and r338709:
------------------------------------------------------------------------
r338703 | bd1976llvm | 2018-08-02 13:27:38 +0200 (Thu, 02 Aug 2018) | 8 lines

[llvm-ar] Correct help text

Corrected and simplified the help text.

It was clearly too difficult to maintain before (see e.g. @227296) making it
simpler and more consistent it should help people keep it up to date.

Differential Revision: https://reviews.llvm.org/D48577
------------------------------------------------------------------------

------------------------------------------------------------------------
r338709 | bd1976llvm | 2018-08-02 14:27:01 +0200 (Thu, 02 Aug 2018) | 3 lines

[llvm-ar] Fix help text test. NFC.

Missed from @338703
------------------------------------------------------------------------

llvm-svn: 338840
2018-08-03 10:12:24 +00:00
Hans Wennborg
e6324b725a Merging r338721:
------------------------------------------------------------------------
r338721 | hahnfeld | 2018-08-02 16:34:08 +0200 (Thu, 02 Aug 2018) | 7 lines

[OMPT] Disable by default on Windows

This is broken per PR36561 and PR36574, so disable it for now until
somebody interested can take a look. OMPT can still be activated manually
by passing -DLIBOMP_OMPT_SUPPORT=ON during configuration.

Differential Revision: https://reviews.llvm.org/D50086
------------------------------------------------------------------------

llvm-svn: 338728
2018-08-02 15:00:25 +00:00
Hans Wennborg
1cca79b00b Merging r338720:
------------------------------------------------------------------------
r338720 | hahnfeld | 2018-08-02 16:34:03 +0200 (Thu, 02 Aug 2018) | 6 lines

[tests] Add annotations for taskloop features

Only supported since GCC 6 and Intel 17.0. However GCC 6.3.0 is
crashing on two of the tests, so disable them as well...

Differential Revision: https://reviews.llvm.org/D50085
------------------------------------------------------------------------

llvm-svn: 338726
2018-08-02 14:59:17 +00:00
Hans Wennborg
ce211412ad Release notes: fix -fno-strict-float-cast-overflow quoting
llvm-svn: 338724
2018-08-02 14:47:40 +00:00
Hans Wennborg
1d910ad0f5 Merging r338580:
------------------------------------------------------------------------
r338580 | jprotze | 2018-08-01 18:15:18 +0200 (Wed, 01 Aug 2018) | 15 lines

[OMPT,tests] Fix taskloop testcase scheduling effects

The taskloop testcase had scheduling effects. Tasks of the taskloop would
sometimes be scheduled before all task were created. The testing is now
split into two phases. First, the task creation on the master is tested,
than the scheduling events of the tasks are tested. Thus, the order of
creation and scheduling events is irrelavant.

Patch by Simon Convent

Reviewed by: protze.joachim, Hahnfeld

Subscribers: openmp-commits

Differential Revision: https://reviews.llvm.org/D50140
------------------------------------------------------------------------

llvm-svn: 338704
2018-08-02 11:33:13 +00:00
Hans Wennborg
f59f1ca9b0 Merging r338554:
------------------------------------------------------------------------
r338554 | bryanpkc | 2018-08-01 15:50:29 +0200 (Wed, 01 Aug 2018) | 11 lines

[AArch64] Fix FCCMP with FP16 operands

Summary: This patch adds support for FCCMP instruction with FP16 operands, avoiding an assertion during instruction selection.

Reviewers: olista01, SjoerdMeijer, t.p.northover, javed.absar

Reviewed By: SjoerdMeijer

Subscribers: kristof.beyls, llvm-commits

Differential Revision: https://reviews.llvm.org/D50115
------------------------------------------------------------------------

llvm-svn: 338692
2018-08-02 09:15:30 +00:00
Hans Wennborg
3ab9eb5378 Merging r338606:
------------------------------------------------------------------------
r338606 | kcc | 2018-08-01 20:29:51 +0200 (Wed, 01 Aug 2018) | 11 lines

Fix sizeof(struct pthread) in glibc 2.14.

Summary: Fixes: https://github.com/google/sanitizers/issues/966

Reviewers: kcc

Reviewed By: kcc

Subscribers: kubamracek

Differential Revision: https://reviews.llvm.org/D50131
------------------------------------------------------------------------

llvm-svn: 338691
2018-08-02 09:03:14 +00:00
Hans Wennborg
5006581f1e Merging r338577:
------------------------------------------------------------------------
r338577 | filcab | 2018-08-01 17:30:14 +0200 (Wed, 01 Aug 2018) | 1 line

Add missing condition
------------------------------------------------------------------------

llvm-svn: 338690
2018-08-02 08:57:59 +00:00
Hans Wennborg
ceb5474679 Merging r338553:
------------------------------------------------------------------------
r338553 | filcab | 2018-08-01 15:41:42 +0200 (Wed, 01 Aug 2018) | 1 line

Use a dummy target so the test passes when default target is for a toolchain implements useIntegratedAs() -> true
------------------------------------------------------------------------

llvm-svn: 338688
2018-08-02 08:53:00 +00:00
Hans Wennborg
5e3af0e9e3 Merging r338552:
------------------------------------------------------------------------
r338552 | filcab | 2018-08-01 15:41:11 +0200 (Wed, 01 Aug 2018) | 1 line

Add REQUIRES: native to a test that assumes it
------------------------------------------------------------------------

llvm-svn: 338687
2018-08-02 08:51:08 +00:00
Hans Wennborg
ad32392b8c Merging r338682:
------------------------------------------------------------------------
r338682 | hans | 2018-08-02 10:10:34 +0200 (Thu, 02 Aug 2018) | 1 line

utils/release/tag.sh: add debuginfo-tests to project list
------------------------------------------------------------------------

llvm-svn: 338683
2018-08-02 08:11:09 +00:00
Hans Wennborg
dd449c2432 Creating release_70 branch off revision 338536
llvm-svn: 338681
2018-08-02 08:09:09 +00:00
Hans Wennborg
63740db57a Merging r338658:
------------------------------------------------------------------------
r338658 | nemanjai | 2018-08-02 02:03:22 +0200 (Thu, 02 Aug 2018) | 13 lines

[PowerPC] Do not round values prior to converting to integer

Adding the FP_ROUND nodes when combining FP_TO_[SU]INT of elements
feeding a BUILD_VECTOR into an FP_TO_[SU]INT of the built vector
loses precision. This patch removes the code that adds these nodes
to true f64 operands. It also adds patterns required to ensure
the code is still vectorized rather than converting individual
elements and inserting into a vector.

Fixes https://bugs.llvm.org/show_bug.cgi?id=38342

Differential Revision: https://reviews.llvm.org/D50121

------------------------------------------------------------------------

llvm-svn: 338678
2018-08-02 08:02:19 +00:00
Hans Wennborg
41c19c9620 Merging r338602:
------------------------------------------------------------------------
r338602 | hans | 2018-08-01 19:51:23 +0200 (Wed, 01 Aug 2018) | 11 lines

Revert r338455 "[constexpr] Support for constant evaluation of __builtin_memcpy and __builtin_memmove (in non-type-punning cases)."

It caused asserts during Chromium builds, see reply on the cfe-commits thread.

> This is intended to permit libc++ to make std::copy etc constexpr
> without sacrificing the optimization that uses memcpy on
> trivially-copyable types.
>
> __builtin_strcpy and __builtin_wcscpy are not handled by this change.
> They'd be straightforward to add, but we haven't encountered a need for
> them just yet.
------------------------------------------------------------------------

llvm-svn: 338674
2018-08-02 06:34:39 +00:00
Hans Wennborg
d32543e590 Generate docs/AttributeReference.rst
$ bin/clang-tblgen -gen-attr-docs -I../cfe.src/include \
    ../cfe.src/include/clang/Basic/Attr.td \
    -o ../cfe.src/docs/AttributeReference.rst

llvm-svn: 338575
2018-08-01 15:28:01 +00:00
Hans Wennborg
f26bd8777b Regenerate ClangCommandLineReference.rst
$ bin/clang-tblgen -gen-opt-docs -I../cfe.src/include \
    -I../cfe.src/include/clang/Driver -I../llvm.src/include \
    ../cfe.src/include/clang/Driver/ClangOptionDocs.td \
    -o ../cfe.src/docs/ClangCommandLineReference.rst

llvm-svn: 338574
2018-08-01 15:27:26 +00:00
Hans Wennborg
73825c44f4 Drop 'svn' suffix from the version number.
llvm-svn: 338573
2018-08-01 15:24:35 +00:00
Hans Wennborg
d81a23816a Drop 'svn' suffix from the version number.
llvm-svn: 338572
2018-08-01 15:24:06 +00:00
Hans Wennborg
d0e85c99da Drop 'svn' suffix from the version number.
llvm-svn: 338571
2018-08-01 15:23:47 +00:00
Hans Wennborg
67cf759ac3 Creating release_70 branch off revision 338536
llvm-svn: 338549
llvm-svn: 338548
llvm-svn: 338547
llvm-svn: 338546
llvm-svn: 338545
llvm-svn: 338544
llvm-svn: 338543
llvm-svn: 338542
llvm-svn: 338541
llvm-svn: 338539
llvm-svn: 338538
2018-08-01 13:31:22 +00:00
21918 changed files with 501935 additions and 2165373 deletions

View File

@@ -1,3 +0,0 @@
{
"conduit_uri" : "https://reviews.llvm.org/"
}

View File

@@ -1,5 +0,0 @@
# The LLVM Compiler Infrastructure
This directory and its subdirectories contain source code for LLVM,
a toolkit for the construction of highly optimized compilers,
optimizers, and runtime environments.

View File

@@ -1,13 +1,10 @@
option(CLANGD_BUILD_XPC "Build XPC Support For Clangd." OFF)
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(CLANGD_BUILD_XPC ON CACHE BOOL "" FORCE)
endif ()
add_subdirectory(clang-apply-replacements)
add_subdirectory(clang-reorder-fields)
add_subdirectory(modularize)
if(CLANG_ENABLE_STATIC_ANALYZER)
add_subdirectory(clang-tidy)
add_subdirectory(clang-tidy-vs)
endif()
add_subdirectory(change-namespace)
add_subdirectory(clang-doc)

View File

@@ -8,8 +8,8 @@ beautification by scripts. The fields are: name (N), email (E), web-address
(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
(S).
N: Aaron Ballman
E: aaron@aaronballman.com
N: Peter Collingbourne
E: peter@pcc.me.uk
D: clang-query
N: Manuel Klimek

View File

@@ -4,7 +4,7 @@ LLVM Release License
University of Illinois/NCSA
Open Source License
Copyright (c) 2007-2019 University of Illinois at Urbana-Champaign.
Copyright (c) 2007-2018 University of Illinois at Urbana-Champaign.
All rights reserved.
Developed by:

View File

@@ -12,7 +12,6 @@ add_clang_library(clangChangeNamespace
clangFormat
clangFrontend
clangLex
clangSerialization
clangTooling
clangToolingCore
)

View File

@@ -7,10 +7,8 @@
//
//===----------------------------------------------------------------------===//
#include "ChangeNamespace.h"
#include "clang/AST/ASTContext.h"
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang::ast_matchers;
@@ -48,7 +46,7 @@ SourceLocation startLocationForType(TypeLoc TLoc) {
return NestedNameSpecifier.getBeginLoc();
TLoc = TLoc.getNextTypeLoc();
}
return TLoc.getBeginLoc();
return TLoc.getLocStart();
}
SourceLocation endLocationForType(TypeLoc TLoc) {
@@ -277,7 +275,7 @@ bool isNestedDeclContext(const DeclContext *D, const DeclContext *Context) {
// Returns true if \p D is visible at \p Loc with DeclContext \p DeclCtx.
bool isDeclVisibleAtLocation(const SourceManager &SM, const Decl *D,
const DeclContext *DeclCtx, SourceLocation Loc) {
SourceLocation DeclLoc = SM.getSpellingLoc(D->getBeginLoc());
SourceLocation DeclLoc = SM.getSpellingLoc(D->getLocStart());
Loc = SM.getSpellingLoc(Loc);
return SM.isBeforeInTranslationUnit(DeclLoc, Loc) &&
(SM.getFileID(DeclLoc) == SM.getFileID(Loc) &&
@@ -285,48 +283,23 @@ bool isDeclVisibleAtLocation(const SourceManager &SM, const Decl *D,
}
// Given a qualified symbol name, returns true if the symbol will be
// incorrectly qualified without leading "::". For example, a symbol
// "nx::ny::Foo" in namespace "na::nx::ny" without leading "::"; a symbol
// "util::X" in namespace "na" can potentially conflict with "na::util" (if this
// exists).
bool conflictInNamespace(const ASTContext &AST, llvm::StringRef QualifiedSymbol,
// incorrectly qualified without leading "::".
bool conflictInNamespace(llvm::StringRef QualifiedSymbol,
llvm::StringRef Namespace) {
auto SymbolSplitted = splitSymbolName(QualifiedSymbol.trim(":"));
assert(!SymbolSplitted.empty());
SymbolSplitted.pop_back(); // We are only interested in namespaces.
if (SymbolSplitted.size() >= 1 && !Namespace.empty()) {
auto SymbolTopNs = SymbolSplitted.front();
if (SymbolSplitted.size() > 1 && !Namespace.empty()) {
auto NsSplitted = splitSymbolName(Namespace.trim(":"));
assert(!NsSplitted.empty());
auto LookupDecl = [&AST](const Decl &Scope,
llvm::StringRef Name) -> const NamedDecl * {
const auto *DC = llvm::dyn_cast<DeclContext>(&Scope);
if (!DC)
return nullptr;
auto LookupRes = DC->lookup(DeclarationName(&AST.Idents.get(Name)));
if (LookupRes.empty())
return nullptr;
return LookupRes.front();
};
// We do not check the outermost namespace since it would not be a
// conflict if it equals to the symbol's outermost namespace and the
// symbol name would have been shortened.
const NamedDecl *Scope =
LookupDecl(*AST.getTranslationUnitDecl(), NsSplitted.front());
// We do not check the outermost namespace since it would not be a conflict
// if it equals to the symbol's outermost namespace and the symbol name
// would have been shortened.
for (auto I = NsSplitted.begin() + 1, E = NsSplitted.end(); I != E; ++I) {
if (*I == SymbolTopNs) // Handles "::ny" in "::nx::ny" case.
if (*I == SymbolSplitted.front())
return true;
// Handles "::util" and "::nx::util" conflicts.
if (Scope) {
if (LookupDecl(*Scope, SymbolTopNs))
return true;
Scope = LookupDecl(*Scope, *I);
}
}
if (Scope && LookupDecl(*Scope, SymbolTopNs))
return true;
}
return false;
}
@@ -450,8 +423,8 @@ void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
typeLoc(IsInMovedNs,
loc(qualType(hasDeclaration(DeclMatcher.bind("from_decl")))),
unless(anyOf(hasParent(typeLoc(loc(qualType(
hasDeclaration(DeclMatcher),
unless(templateSpecializationType()))))),
allOf(hasDeclaration(DeclMatcher),
unless(templateSpecializationType())))))),
hasParent(nestedNameSpecifierLoc()),
hasAncestor(isImplicit()),
hasAncestor(UsingShadowDeclInClass),
@@ -505,12 +478,13 @@ void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
hasAncestor(namespaceDecl(isAnonymous())),
hasAncestor(cxxRecordDecl()))),
hasParent(namespaceDecl()));
Finder->addMatcher(expr(hasAncestor(decl().bind("dc")), IsInMovedNs,
unless(hasAncestor(isImplicit())),
anyOf(callExpr(callee(FuncMatcher)).bind("call"),
declRefExpr(to(FuncMatcher.bind("func_decl")))
.bind("func_ref"))),
this);
Finder->addMatcher(
expr(allOf(hasAncestor(decl().bind("dc")), IsInMovedNs,
unless(hasAncestor(isImplicit())),
anyOf(callExpr(callee(FuncMatcher)).bind("call"),
declRefExpr(to(FuncMatcher.bind("func_decl")))
.bind("func_ref")))),
this);
auto GlobalVarMatcher = varDecl(
hasGlobalStorage(), hasParent(namespaceDecl()),
@@ -660,7 +634,7 @@ static SourceLocation getLocAfterNamespaceLBrace(const NamespaceDecl *NsDecl,
const SourceManager &SM,
const LangOptions &LangOpts) {
std::unique_ptr<Lexer> Lex =
getLexerStartingFromLoc(NsDecl->getBeginLoc(), SM, LangOpts);
getLexerStartingFromLoc(NsDecl->getLocStart(), SM, LangOpts);
assert(Lex.get() &&
"Failed to create lexer from the beginning of namespace.");
if (!Lex.get())
@@ -735,8 +709,8 @@ void ChangeNamespaceTool::moveOldNamespace(
void ChangeNamespaceTool::moveClassForwardDeclaration(
const ast_matchers::MatchFinder::MatchResult &Result,
const NamedDecl *FwdDecl) {
SourceLocation Start = FwdDecl->getBeginLoc();
SourceLocation End = FwdDecl->getEndLoc();
SourceLocation Start = FwdDecl->getLocStart();
SourceLocation End = FwdDecl->getLocEnd();
const SourceManager &SM = *Result.SourceManager;
SourceLocation AfterSemi = Lexer::findLocationAfterToken(
End, tok::semi, SM, Result.Context->getLangOpts(),
@@ -870,16 +844,15 @@ void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext(
}
}
}
bool Conflict = conflictInNamespace(DeclCtx->getParentASTContext(),
ReplaceName, NewNamespace);
// If the new nested name in the new namespace is the same as it was in the
// old namespace, we don't create replacement unless there can be ambiguity.
if ((NestedName == ReplaceName && !Conflict) ||
// old namespace, we don't create replacement.
if (NestedName == ReplaceName ||
(NestedName.startswith("::") && NestedName.drop_front(2) == ReplaceName))
return;
// If the reference need to be fully-qualified, add a leading "::" unless
// NewNamespace is the global namespace.
if (ReplaceName == FromDeclName && !NewNamespace.empty() && Conflict)
if (ReplaceName == FromDeclName && !NewNamespace.empty() &&
conflictInNamespace(ReplaceName, NewNamespace))
ReplaceName = "::" + ReplaceName;
addReplacementOrDie(Start, End, ReplaceName, *Result.SourceManager,
&FileToReplacements);
@@ -906,7 +879,7 @@ void ChangeNamespaceTool::fixTypeLoc(
if (!llvm::StringRef(D->getQualifiedNameAsString())
.startswith(OldNamespace + "::"))
return false;
auto ExpansionLoc = Result.SourceManager->getExpansionLoc(D->getBeginLoc());
auto ExpansionLoc = Result.SourceManager->getExpansionLoc(D->getLocStart());
if (ExpansionLoc.isInvalid())
return false;
llvm::StringRef Filename = Result.SourceManager->getFilename(ExpansionLoc);
@@ -937,8 +910,8 @@ void ChangeNamespaceTool::fixTypeLoc(
void ChangeNamespaceTool::fixUsingShadowDecl(
const ast_matchers::MatchFinder::MatchResult &Result,
const UsingDecl *UsingDeclaration) {
SourceLocation Start = UsingDeclaration->getBeginLoc();
SourceLocation End = UsingDeclaration->getEndLoc();
SourceLocation Start = UsingDeclaration->getLocStart();
SourceLocation End = UsingDeclaration->getLocEnd();
if (Start.isInvalid() || End.isInvalid())
return;
@@ -1016,8 +989,7 @@ void ChangeNamespaceTool::onEndOfTranslationUnit() {
// Add replacements referring to the changed code to existing replacements,
// which refers to the original code.
Replaces = Replaces.merge(NewReplacements);
auto Style =
format::getStyle(format::DefaultFormatStyle, FilePath, FallbackStyle);
auto Style = format::getStyle("file", FilePath, FallbackStyle);
if (!Style) {
llvm::errs() << llvm::toString(Style.takeError()) << "\n";
continue;

View File

@@ -16,7 +16,6 @@ target_link_libraries(clang-change-namespace
clangFormat
clangFrontend
clangRewrite
clangSerialization
clangTooling
clangToolingCore
)

View File

@@ -125,8 +125,7 @@ std::error_code collectReplacementsFromDirectory(
}
/// \brief Extract replacements from collected TranslationUnitReplacements and
/// TranslationUnitDiagnostics and group them per file. Identical replacements
/// from diagnostics are deduplicated.
/// TranslationUnitDiagnostics and group them per file.
///
/// \param[in] TUs Collection of all found and deserialized
/// TranslationUnitReplacements.
@@ -143,20 +142,10 @@ groupReplacements(const TUReplacements &TUs, const TUDiagnostics &TUDs,
llvm::DenseMap<const FileEntry *, std::vector<tooling::Replacement>>
GroupedReplacements;
// Deduplicate identical replacements in diagnostics.
// FIXME: Find an efficient way to deduplicate on diagnostics level.
llvm::DenseMap<const FileEntry *, std::set<tooling::Replacement>>
DiagReplacements;
auto AddToGroup = [&](const tooling::Replacement &R, bool FromDiag) {
auto AddToGroup = [&](const tooling::Replacement &R) {
// Use the file manager to deduplicate paths. FileEntries are
// automatically canonicalized.
if (const FileEntry *Entry = SM.getFileManager().getFile(R.getFilePath())) {
if (FromDiag) {
auto &Replaces = DiagReplacements[Entry];
if (!Replaces.insert(R).second)
return;
}
GroupedReplacements[Entry].push_back(R);
} else if (Warned.insert(R.getFilePath()).second) {
errs() << "Described file '" << R.getFilePath()
@@ -166,13 +155,13 @@ groupReplacements(const TUReplacements &TUs, const TUDiagnostics &TUDs,
for (const auto &TU : TUs)
for (const tooling::Replacement &R : TU.Replacements)
AddToGroup(R, false);
AddToGroup(R);
for (const auto &TU : TUDs)
for (const auto &D : TU.Diagnostics)
for (const auto &Fix : D.Fix)
for (const tooling::Replacement &R : Fix.second)
AddToGroup(R, true);
AddToGroup(R);
// Sort replacements per file to keep consistent behavior when
// clang-apply-replacements run on differents machine.

View File

@@ -97,8 +97,8 @@ int main(int argc, char **argv) {
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts.get());
// Determine a formatting style from options.
auto FormatStyleOrError = format::getStyle(FormatStyleOpt, FormatStyleConfig,
format::DefaultFallbackStyle);
auto FormatStyleOrError =
format::getStyle(FormatStyleOpt, FormatStyleConfig, "LLVM");
if (!FormatStyleOrError) {
llvm::errs() << llvm::toString(FormatStyleOrError.takeError()) << "\n";
return 1;

View File

@@ -10,7 +10,6 @@
#include "BitcodeReader.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/raw_ostream.h"
namespace clang {
@@ -18,53 +17,49 @@ namespace doc {
using Record = llvm::SmallVector<uint64_t, 1024>;
llvm::Error decodeRecord(Record R, llvm::SmallVectorImpl<char> &Field,
llvm::StringRef Blob) {
bool decodeRecord(Record R, llvm::SmallVectorImpl<char> &Field,
llvm::StringRef Blob) {
Field.assign(Blob.begin(), Blob.end());
return llvm::Error::success();
return true;
}
llvm::Error decodeRecord(Record R, SymbolID &Field, llvm::StringRef Blob) {
bool decodeRecord(Record R, SymbolID &Field, llvm::StringRef Blob) {
if (R[0] != BitCodeConstants::USRHashSize)
return llvm::make_error<llvm::StringError>("Incorrect USR size.\n",
llvm::inconvertibleErrorCode());
return false;
// First position in the record is the length of the following array, so we
// copy the following elements to the field.
for (int I = 0, E = R[0]; I < E; ++I)
Field[I] = R[I + 1];
return llvm::Error::success();
return true;
}
llvm::Error decodeRecord(Record R, bool &Field, llvm::StringRef Blob) {
bool decodeRecord(Record R, bool &Field, llvm::StringRef Blob) {
Field = R[0] != 0;
return llvm::Error::success();
return true;
}
llvm::Error decodeRecord(Record R, int &Field, llvm::StringRef Blob) {
bool decodeRecord(Record R, int &Field, llvm::StringRef Blob) {
if (R[0] > INT_MAX)
return llvm::make_error<llvm::StringError>("Integer too large to parse.\n",
llvm::inconvertibleErrorCode());
return false;
Field = (int)R[0];
return llvm::Error::success();
return true;
}
llvm::Error decodeRecord(Record R, AccessSpecifier &Field,
llvm::StringRef Blob) {
bool decodeRecord(Record R, AccessSpecifier &Field, llvm::StringRef Blob) {
switch (R[0]) {
case AS_public:
case AS_private:
case AS_protected:
case AS_none:
Field = (AccessSpecifier)R[0];
return llvm::Error::success();
return true;
default:
return llvm::make_error<llvm::StringError>(
"Invalid value for AccessSpecifier.\n", llvm::inconvertibleErrorCode());
return false;
}
}
llvm::Error decodeRecord(Record R, TagTypeKind &Field, llvm::StringRef Blob) {
bool decodeRecord(Record R, TagTypeKind &Field, llvm::StringRef Blob) {
switch (R[0]) {
case TTK_Struct:
case TTK_Interface:
@@ -72,23 +67,21 @@ llvm::Error decodeRecord(Record R, TagTypeKind &Field, llvm::StringRef Blob) {
case TTK_Class:
case TTK_Enum:
Field = (TagTypeKind)R[0];
return llvm::Error::success();
return true;
default:
return llvm::make_error<llvm::StringError>(
"Invalid value for TagTypeKind.\n", llvm::inconvertibleErrorCode());
return false;
}
}
llvm::Error decodeRecord(Record R, llvm::Optional<Location> &Field,
llvm::StringRef Blob) {
bool decodeRecord(Record R, llvm::Optional<Location> &Field,
llvm::StringRef Blob) {
if (R[0] > INT_MAX)
return llvm::make_error<llvm::StringError>("Integer too large to parse.\n",
llvm::inconvertibleErrorCode());
return false;
Field.emplace((int)R[0], Blob);
return llvm::Error::success();
return true;
}
llvm::Error decodeRecord(Record R, InfoType &Field, llvm::StringRef Blob) {
bool decodeRecord(Record R, InfoType &Field, llvm::StringRef Blob) {
switch (auto IT = static_cast<InfoType>(R[0])) {
case InfoType::IT_namespace:
case InfoType::IT_record:
@@ -96,67 +89,58 @@ llvm::Error decodeRecord(Record R, InfoType &Field, llvm::StringRef Blob) {
case InfoType::IT_default:
case InfoType::IT_enum:
Field = IT;
return llvm::Error::success();
return true;
}
return llvm::make_error<llvm::StringError>("Invalid value for InfoType.\n",
llvm::inconvertibleErrorCode());
return false;
}
llvm::Error decodeRecord(Record R, FieldId &Field, llvm::StringRef Blob) {
bool decodeRecord(Record R, FieldId &Field, llvm::StringRef Blob) {
switch (auto F = static_cast<FieldId>(R[0])) {
case FieldId::F_namespace:
case FieldId::F_parent:
case FieldId::F_vparent:
case FieldId::F_type:
case FieldId::F_child_namespace:
case FieldId::F_child_record:
case FieldId::F_default:
Field = F;
return llvm::Error::success();
return true;
}
return llvm::make_error<llvm::StringError>("Invalid value for FieldId.\n",
llvm::inconvertibleErrorCode());
return false;
}
llvm::Error decodeRecord(Record R,
llvm::SmallVectorImpl<llvm::SmallString<16>> &Field,
llvm::StringRef Blob) {
bool decodeRecord(Record R, llvm::SmallVectorImpl<llvm::SmallString<16>> &Field,
llvm::StringRef Blob) {
Field.push_back(Blob);
return llvm::Error::success();
return true;
}
llvm::Error decodeRecord(Record R, llvm::SmallVectorImpl<Location> &Field,
llvm::StringRef Blob) {
bool decodeRecord(Record R, llvm::SmallVectorImpl<Location> &Field,
llvm::StringRef Blob) {
if (R[0] > INT_MAX)
return llvm::make_error<llvm::StringError>("Integer too large to parse.\n",
llvm::inconvertibleErrorCode());
return false;
Field.emplace_back((int)R[0], Blob);
return llvm::Error::success();
return true;
}
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
const unsigned VersionNo) {
bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
const unsigned VersionNo) {
if (ID == VERSION && R[0] == VersionNo)
return llvm::Error::success();
return llvm::make_error<llvm::StringError>(
"Mismatched bitcode version number.\n", llvm::inconvertibleErrorCode());
return true;
return false;
}
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
NamespaceInfo *I) {
bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
NamespaceInfo *I) {
switch (ID) {
case NAMESPACE_USR:
return decodeRecord(R, I->USR, Blob);
case NAMESPACE_NAME:
return decodeRecord(R, I->Name, Blob);
default:
return llvm::make_error<llvm::StringError>(
"Invalid field for NamespaceInfo.\n", llvm::inconvertibleErrorCode());
return false;
}
}
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
RecordInfo *I) {
bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, RecordInfo *I) {
switch (ID) {
case RECORD_USR:
return decodeRecord(R, I->USR, Blob);
@@ -169,13 +153,11 @@ llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
case RECORD_TAG_TYPE:
return decodeRecord(R, I->TagType, Blob);
default:
return llvm::make_error<llvm::StringError>(
"Invalid field for RecordInfo.\n", llvm::inconvertibleErrorCode());
return false;
}
}
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
EnumInfo *I) {
bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, EnumInfo *I) {
switch (ID) {
case ENUM_USR:
return decodeRecord(R, I->USR, Blob);
@@ -190,13 +172,11 @@ llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
case ENUM_SCOPED:
return decodeRecord(R, I->Scoped, Blob);
default:
return llvm::make_error<llvm::StringError>("Invalid field for EnumInfo.\n",
llvm::inconvertibleErrorCode());
return false;
}
}
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
FunctionInfo *I) {
bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, FunctionInfo *I) {
switch (ID) {
case FUNCTION_USR:
return decodeRecord(R, I->USR, Blob);
@@ -211,42 +191,37 @@ llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
case FUNCTION_IS_METHOD:
return decodeRecord(R, I->IsMethod, Blob);
default:
return llvm::make_error<llvm::StringError>(
"Invalid field for FunctionInfo.\n", llvm::inconvertibleErrorCode());
return false;
}
}
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
TypeInfo *I) {
return llvm::Error::success();
bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, TypeInfo *I) {
return true;
}
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
FieldTypeInfo *I) {
bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
FieldTypeInfo *I) {
switch (ID) {
case FIELD_TYPE_NAME:
return decodeRecord(R, I->Name, Blob);
default:
return llvm::make_error<llvm::StringError>("Invalid field for TypeInfo.\n",
llvm::inconvertibleErrorCode());
return false;
}
}
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
MemberTypeInfo *I) {
bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
MemberTypeInfo *I) {
switch (ID) {
case MEMBER_TYPE_NAME:
return decodeRecord(R, I->Name, Blob);
case MEMBER_TYPE_ACCESS:
return decodeRecord(R, I->Access, Blob);
default:
return llvm::make_error<llvm::StringError>(
"Invalid field for MemberTypeInfo.\n", llvm::inconvertibleErrorCode());
return false;
}
}
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
CommentInfo *I) {
bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, CommentInfo *I) {
switch (ID) {
case COMMENT_KIND:
return decodeRecord(R, I->Kind, Blob);
@@ -271,13 +246,12 @@ llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
case COMMENT_EXPLICIT:
return decodeRecord(R, I->Explicit, Blob);
default:
return llvm::make_error<llvm::StringError>(
"Invalid field for CommentInfo.\n", llvm::inconvertibleErrorCode());
return false;
}
}
llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
Reference *I, FieldId &F) {
bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, Reference *I,
FieldId &F) {
switch (ID) {
case REFERENCE_USR:
return decodeRecord(R, I->USR, Blob);
@@ -288,214 +262,162 @@ llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
case REFERENCE_FIELD:
return decodeRecord(R, F, Blob);
default:
return llvm::make_error<llvm::StringError>("Invalid field for Reference.\n",
llvm::inconvertibleErrorCode());
return false;
}
}
template <typename T> llvm::Expected<CommentInfo *> getCommentInfo(T I) {
return llvm::make_error<llvm::StringError>(
"Invalid type cannot contain CommentInfo.\n",
llvm::inconvertibleErrorCode());
template <typename T> CommentInfo *getCommentInfo(T I) {
llvm::errs() << "Cannot have comment subblock.\n";
exit(1);
}
template <> llvm::Expected<CommentInfo *> getCommentInfo(FunctionInfo *I) {
template <> CommentInfo *getCommentInfo(FunctionInfo *I) {
I->Description.emplace_back();
return &I->Description.back();
}
template <> llvm::Expected<CommentInfo *> getCommentInfo(NamespaceInfo *I) {
template <> CommentInfo *getCommentInfo(NamespaceInfo *I) {
I->Description.emplace_back();
return &I->Description.back();
}
template <> llvm::Expected<CommentInfo *> getCommentInfo(RecordInfo *I) {
template <> CommentInfo *getCommentInfo(RecordInfo *I) {
I->Description.emplace_back();
return &I->Description.back();
}
template <> llvm::Expected<CommentInfo *> getCommentInfo(EnumInfo *I) {
template <> CommentInfo *getCommentInfo(EnumInfo *I) {
I->Description.emplace_back();
return &I->Description.back();
}
template <> llvm::Expected<CommentInfo *> getCommentInfo(CommentInfo *I) {
template <> CommentInfo *getCommentInfo(CommentInfo *I) {
I->Children.emplace_back(llvm::make_unique<CommentInfo>());
return I->Children.back().get();
}
template <>
llvm::Expected<CommentInfo *> getCommentInfo(std::unique_ptr<CommentInfo> &I) {
template <> CommentInfo *getCommentInfo(std::unique_ptr<CommentInfo> &I) {
return getCommentInfo(I.get());
}
template <typename T, typename TTypeInfo>
llvm::Error addTypeInfo(T I, TTypeInfo &&TI) {
return llvm::make_error<llvm::StringError>(
"Invalid type cannot contain TypeInfo.\n",
llvm::inconvertibleErrorCode());
}
template <> llvm::Error addTypeInfo(RecordInfo *I, MemberTypeInfo &&T) {
I->Members.emplace_back(std::move(T));
return llvm::Error::success();
}
template <> llvm::Error addTypeInfo(FunctionInfo *I, TypeInfo &&T) {
I->ReturnType = std::move(T);
return llvm::Error::success();
}
template <> llvm::Error addTypeInfo(FunctionInfo *I, FieldTypeInfo &&T) {
I->Params.emplace_back(std::move(T));
return llvm::Error::success();
}
template <typename T> llvm::Error addReference(T I, Reference &&R, FieldId F) {
return llvm::make_error<llvm::StringError>(
"Invalid type cannot contain Reference\n",
llvm::inconvertibleErrorCode());
}
template <> llvm::Error addReference(TypeInfo *I, Reference &&R, FieldId F) {
switch (F) {
case FieldId::F_type:
I->Type = std::move(R);
return llvm::Error::success();
default:
return llvm::make_error<llvm::StringError>(
"Invalid type cannot contain Reference.\n",
llvm::inconvertibleErrorCode());
}
}
template <>
llvm::Error addReference(FieldTypeInfo *I, Reference &&R, FieldId F) {
switch (F) {
case FieldId::F_type:
I->Type = std::move(R);
return llvm::Error::success();
default:
return llvm::make_error<llvm::StringError>(
"Invalid type cannot contain Reference.\n",
llvm::inconvertibleErrorCode());
}
}
template <>
llvm::Error addReference(MemberTypeInfo *I, Reference &&R, FieldId F) {
switch (F) {
case FieldId::F_type:
I->Type = std::move(R);
return llvm::Error::success();
default:
return llvm::make_error<llvm::StringError>(
"Invalid type cannot contain Reference.\n",
llvm::inconvertibleErrorCode());
}
}
template <> llvm::Error addReference(EnumInfo *I, Reference &&R, FieldId F) {
switch (F) {
case FieldId::F_namespace:
I->Namespace.emplace_back(std::move(R));
return llvm::Error::success();
default:
return llvm::make_error<llvm::StringError>(
"Invalid type cannot contain Reference.\n",
llvm::inconvertibleErrorCode());
}
}
template <>
llvm::Error addReference(NamespaceInfo *I, Reference &&R, FieldId F) {
switch (F) {
case FieldId::F_namespace:
I->Namespace.emplace_back(std::move(R));
return llvm::Error::success();
case FieldId::F_child_namespace:
I->ChildNamespaces.emplace_back(std::move(R));
return llvm::Error::success();
case FieldId::F_child_record:
I->ChildRecords.emplace_back(std::move(R));
return llvm::Error::success();
default:
return llvm::make_error<llvm::StringError>(
"Invalid type cannot contain Reference.\n",
llvm::inconvertibleErrorCode());
}
}
template <>
llvm::Error addReference(FunctionInfo *I, Reference &&R, FieldId F) {
switch (F) {
case FieldId::F_namespace:
I->Namespace.emplace_back(std::move(R));
return llvm::Error::success();
case FieldId::F_parent:
I->Parent = std::move(R);
return llvm::Error::success();
default:
return llvm::make_error<llvm::StringError>(
"Invalid type cannot contain Reference.\n",
llvm::inconvertibleErrorCode());
}
}
template <> llvm::Error addReference(RecordInfo *I, Reference &&R, FieldId F) {
switch (F) {
case FieldId::F_namespace:
I->Namespace.emplace_back(std::move(R));
return llvm::Error::success();
case FieldId::F_parent:
I->Parents.emplace_back(std::move(R));
return llvm::Error::success();
case FieldId::F_vparent:
I->VirtualParents.emplace_back(std::move(R));
return llvm::Error::success();
case FieldId::F_child_record:
I->ChildRecords.emplace_back(std::move(R));
return llvm::Error::success();
default:
return llvm::make_error<llvm::StringError>(
"Invalid type cannot contain Reference.\n",
llvm::inconvertibleErrorCode());
}
}
template <typename T, typename ChildInfoType>
void addChild(T I, ChildInfoType &&R) {
llvm::errs() << "Invalid child type for info.\n";
void addTypeInfo(T I, TTypeInfo &&TI) {
llvm::errs() << "Invalid type for info.\n";
exit(1);
}
template <> void addChild(NamespaceInfo *I, FunctionInfo &&R) {
I->ChildFunctions.emplace_back(std::move(R));
template <> void addTypeInfo(RecordInfo *I, MemberTypeInfo &&T) {
I->Members.emplace_back(std::move(T));
}
template <> void addChild(NamespaceInfo *I, EnumInfo &&R) {
I->ChildEnums.emplace_back(std::move(R));
template <> void addTypeInfo(FunctionInfo *I, TypeInfo &&T) {
I->ReturnType = std::move(T);
}
template <> void addChild(RecordInfo *I, FunctionInfo &&R) {
I->ChildFunctions.emplace_back(std::move(R));
template <> void addTypeInfo(FunctionInfo *I, FieldTypeInfo &&T) {
I->Params.emplace_back(std::move(T));
}
template <> void addChild(RecordInfo *I, EnumInfo &&R) {
I->ChildEnums.emplace_back(std::move(R));
template <typename T> void addReference(T I, Reference &&R, FieldId F) {
llvm::errs() << "Invalid field type for info.\n";
exit(1);
}
template <> void addReference(TypeInfo *I, Reference &&R, FieldId F) {
switch (F) {
case FieldId::F_type:
I->Type = std::move(R);
break;
default:
llvm::errs() << "Invalid field type for info.\n";
exit(1);
}
}
template <> void addReference(FieldTypeInfo *I, Reference &&R, FieldId F) {
switch (F) {
case FieldId::F_type:
I->Type = std::move(R);
break;
default:
llvm::errs() << "Invalid field type for info.\n";
exit(1);
}
}
template <> void addReference(MemberTypeInfo *I, Reference &&R, FieldId F) {
switch (F) {
case FieldId::F_type:
I->Type = std::move(R);
break;
default:
llvm::errs() << "Invalid field type for info.\n";
exit(1);
}
}
template <> void addReference(EnumInfo *I, Reference &&R, FieldId F) {
switch (F) {
case FieldId::F_namespace:
I->Namespace.emplace_back(std::move(R));
break;
default:
llvm::errs() << "Invalid field type for info.\n";
exit(1);
}
}
template <> void addReference(NamespaceInfo *I, Reference &&R, FieldId F) {
switch (F) {
case FieldId::F_namespace:
I->Namespace.emplace_back(std::move(R));
break;
default:
llvm::errs() << "Invalid field type for info.\n";
exit(1);
}
}
template <> void addReference(FunctionInfo *I, Reference &&R, FieldId F) {
switch (F) {
case FieldId::F_namespace:
I->Namespace.emplace_back(std::move(R));
break;
case FieldId::F_parent:
I->Parent = std::move(R);
break;
default:
llvm::errs() << "Invalid field type for info.\n";
exit(1);
}
}
template <> void addReference(RecordInfo *I, Reference &&R, FieldId F) {
switch (F) {
case FieldId::F_namespace:
I->Namespace.emplace_back(std::move(R));
break;
case FieldId::F_parent:
I->Parents.emplace_back(std::move(R));
break;
case FieldId::F_vparent:
I->VirtualParents.emplace_back(std::move(R));
break;
default:
llvm::errs() << "Invalid field type for info.\n";
exit(1);
}
}
// Read records from bitcode into a given info.
template <typename T>
llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, T I) {
template <typename T> bool ClangDocBitcodeReader::readRecord(unsigned ID, T I) {
Record R;
llvm::StringRef Blob;
unsigned RecID = Stream.readRecord(ID, R, &Blob);
return parseRecord(R, RecID, Blob, I);
}
template <>
llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, Reference *I) {
template <> bool ClangDocBitcodeReader::readRecord(unsigned ID, Reference *I) {
Record R;
llvm::StringRef Blob;
unsigned RecID = Stream.readRecord(ID, R, &Blob);
@@ -503,11 +425,9 @@ llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, Reference *I) {
}
// Read a block of records into a single info.
template <typename T>
llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, T I) {
template <typename T> bool ClangDocBitcodeReader::readBlock(unsigned ID, T I) {
if (Stream.EnterSubBlock(ID))
return llvm::make_error<llvm::StringError>("Unable to enter subblock.\n",
llvm::inconvertibleErrorCode());
return false;
while (true) {
unsigned BlockOrCode = 0;
@@ -515,87 +435,66 @@ llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, T I) {
switch (Res) {
case Cursor::BadBlock:
return llvm::make_error<llvm::StringError>(
"Bad block found.\n", llvm::inconvertibleErrorCode());
return false;
case Cursor::BlockEnd:
return llvm::Error::success();
return true;
case Cursor::BlockBegin:
if (auto Err = readSubBlock(BlockOrCode, I)) {
if (!Stream.SkipBlock())
continue;
return Err;
}
if (readSubBlock(BlockOrCode, I))
continue;
if (!Stream.SkipBlock())
return false;
continue;
case Cursor::Record:
break;
}
if (auto Err = readRecord(BlockOrCode, I))
return Err;
if (!readRecord(BlockOrCode, I))
return false;
}
}
template <typename T>
llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) {
bool ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) {
switch (ID) {
// Blocks can only have Comment, Reference, TypeInfo, FunctionInfo, or
// EnumInfo subblocks
case BI_COMMENT_BLOCK_ID: {
auto Comment = getCommentInfo(I);
if (!Comment)
return Comment.takeError();
if (auto Err = readBlock(ID, Comment.get()))
return Err;
return llvm::Error::success();
}
// Blocks can only have Comment, Reference, or TypeInfo subblocks
case BI_COMMENT_BLOCK_ID:
if (readBlock(ID, getCommentInfo(I)))
return true;
return false;
case BI_TYPE_BLOCK_ID: {
TypeInfo TI;
if (auto Err = readBlock(ID, &TI))
return Err;
if (auto Err = addTypeInfo(I, std::move(TI)))
return Err;
return llvm::Error::success();
if (readBlock(ID, &TI)) {
addTypeInfo(I, std::move(TI));
return true;
}
return false;
}
case BI_FIELD_TYPE_BLOCK_ID: {
FieldTypeInfo TI;
if (auto Err = readBlock(ID, &TI))
return Err;
if (auto Err = addTypeInfo(I, std::move(TI)))
return Err;
return llvm::Error::success();
if (readBlock(ID, &TI)) {
addTypeInfo(I, std::move(TI));
return true;
}
return false;
}
case BI_MEMBER_TYPE_BLOCK_ID: {
MemberTypeInfo TI;
if (auto Err = readBlock(ID, &TI))
return Err;
if (auto Err = addTypeInfo(I, std::move(TI)))
return Err;
return llvm::Error::success();
if (readBlock(ID, &TI)) {
addTypeInfo(I, std::move(TI));
return true;
}
return false;
}
case BI_REFERENCE_BLOCK_ID: {
Reference R;
if (auto Err = readBlock(ID, &R))
return Err;
if (auto Err = addReference(I, std::move(R), CurrentReferenceField))
return Err;
return llvm::Error::success();
}
case BI_FUNCTION_BLOCK_ID: {
FunctionInfo F;
if (auto Err = readBlock(ID, &F))
return Err;
addChild(I, std::move(F));
return llvm::Error::success();
}
case BI_ENUM_BLOCK_ID: {
EnumInfo E;
if (auto Err = readBlock(ID, &E))
return Err;
addChild(I, std::move(E));
return llvm::Error::success();
if (readBlock(ID, &R)) {
addReference(I, std::move(R), CurrentReferenceField);
return true;
}
return false;
}
default:
return llvm::make_error<llvm::StringError>("Invalid subblock type.\n",
llvm::inconvertibleErrorCode());
llvm::errs() << "Invalid subblock type.\n";
return false;
}
}
@@ -627,41 +526,37 @@ ClangDocBitcodeReader::skipUntilRecordOrBlock(unsigned &BlockOrRecordID) {
llvm_unreachable("Premature stream end.");
}
llvm::Error ClangDocBitcodeReader::validateStream() {
bool ClangDocBitcodeReader::validateStream() {
if (Stream.AtEndOfStream())
return llvm::make_error<llvm::StringError>("Premature end of stream.\n",
llvm::inconvertibleErrorCode());
return false;
// Sniff for the signature.
if (Stream.Read(8) != BitCodeConstants::Signature[0] ||
Stream.Read(8) != BitCodeConstants::Signature[1] ||
Stream.Read(8) != BitCodeConstants::Signature[2] ||
Stream.Read(8) != BitCodeConstants::Signature[3])
return llvm::make_error<llvm::StringError>("Invalid bitcode signature.\n",
llvm::inconvertibleErrorCode());
return llvm::Error::success();
return false;
return true;
}
llvm::Error ClangDocBitcodeReader::readBlockInfoBlock() {
bool ClangDocBitcodeReader::readBlockInfoBlock() {
BlockInfo = Stream.ReadBlockInfoBlock();
if (!BlockInfo)
return llvm::make_error<llvm::StringError>(
"Unable to parse BlockInfoBlock.\n", llvm::inconvertibleErrorCode());
return false;
Stream.setBlockInfo(&*BlockInfo);
return llvm::Error::success();
return true;
}
template <typename T>
llvm::Expected<std::unique_ptr<Info>>
ClangDocBitcodeReader::createInfo(unsigned ID) {
std::unique_ptr<Info> ClangDocBitcodeReader::createInfo(unsigned ID) {
std::unique_ptr<Info> I = llvm::make_unique<T>();
if (auto Err = readBlock(ID, static_cast<T *>(I.get())))
return std::move(Err);
return std::unique_ptr<Info>{std::move(I)};;
if (readBlock(ID, static_cast<T *>(I.get())))
return I;
llvm::errs() << "Error reading from block.\n";
return nullptr;
}
llvm::Expected<std::unique_ptr<Info>>
ClangDocBitcodeReader::readBlockToInfo(unsigned ID) {
std::unique_ptr<Info> ClangDocBitcodeReader::readBlockToInfo(unsigned ID) {
switch (ID) {
case BI_NAMESPACE_BLOCK_ID:
return createInfo<NamespaceInfo>(ID);
@@ -672,24 +567,23 @@ ClangDocBitcodeReader::readBlockToInfo(unsigned ID) {
case BI_FUNCTION_BLOCK_ID:
return createInfo<FunctionInfo>(ID);
default:
return llvm::make_error<llvm::StringError>("Cannot create info.\n",
llvm::inconvertibleErrorCode());
llvm::errs() << "Error reading from block.\n";
return nullptr;
}
}
// Entry point
llvm::Expected<std::vector<std::unique_ptr<Info>>>
ClangDocBitcodeReader::readBitcode() {
std::vector<std::unique_ptr<Info>> ClangDocBitcodeReader::readBitcode() {
std::vector<std::unique_ptr<Info>> Infos;
if (auto Err = validateStream())
return std::move(Err);
if (!validateStream())
return Infos;
// Read the top level blocks.
while (!Stream.AtEndOfStream()) {
unsigned Code = Stream.ReadCode();
if (Code != llvm::bitc::ENTER_SUBBLOCK)
return llvm::make_error<llvm::StringError>(
"No blocks in input.\n", llvm::inconvertibleErrorCode());
return Infos;
unsigned ID = Stream.ReadSubBlockID();
switch (ID) {
// NamedType and Comment blocks should not appear at the top level
@@ -698,32 +592,30 @@ ClangDocBitcodeReader::readBitcode() {
case BI_MEMBER_TYPE_BLOCK_ID:
case BI_COMMENT_BLOCK_ID:
case BI_REFERENCE_BLOCK_ID:
return llvm::make_error<llvm::StringError>(
"Invalid top level block.\n", llvm::inconvertibleErrorCode());
llvm::errs() << "Invalid top level block.\n";
return Infos;
case BI_NAMESPACE_BLOCK_ID:
case BI_RECORD_BLOCK_ID:
case BI_ENUM_BLOCK_ID:
case BI_FUNCTION_BLOCK_ID: {
auto InfoOrErr = readBlockToInfo(ID);
if (!InfoOrErr)
return InfoOrErr.takeError();
Infos.emplace_back(std::move(InfoOrErr.get()));
continue;
}
case BI_FUNCTION_BLOCK_ID:
if (std::unique_ptr<Info> I = readBlockToInfo(ID)) {
Infos.emplace_back(std::move(I));
}
return Infos;
case BI_VERSION_BLOCK_ID:
if (auto Err = readBlock(ID, VersionNumber))
return std::move(Err);
continue;
if (readBlock(ID, VersionNumber))
continue;
return Infos;
case llvm::bitc::BLOCKINFO_BLOCK_ID:
if (auto Err = readBlockInfoBlock())
return std::move(Err);
continue;
if (readBlockInfoBlock())
continue;
return Infos;
default:
if (!Stream.SkipBlock())
continue;
}
}
return std::move(Infos);
return Infos;
}
} // namespace doc

View File

@@ -19,10 +19,8 @@
#include "BitcodeWriter.h"
#include "Representation.h"
#include "clang/AST/AST.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Support/Error.h"
namespace clang {
namespace doc {
@@ -33,37 +31,36 @@ public:
ClangDocBitcodeReader(llvm::BitstreamCursor &Stream) : Stream(Stream) {}
// Main entry point, calls readBlock to read each block in the given stream.
llvm::Expected<std::vector<std::unique_ptr<Info>>> readBitcode();
std::vector<std::unique_ptr<Info>> readBitcode();
private:
enum class Cursor { BadBlock = 1, Record, BlockEnd, BlockBegin };
// Top level parsing
llvm::Error validateStream();
llvm::Error readVersion();
llvm::Error readBlockInfoBlock();
bool validateStream();
bool readVersion();
bool readBlockInfoBlock();
// Read a block of records into a single Info struct, calls readRecord on each
// record found.
template <typename T> llvm::Error readBlock(unsigned ID, T I);
template <typename T> bool readBlock(unsigned ID, T I);
// Step through a block of records to find the next data field.
template <typename T> llvm::Error readSubBlock(unsigned ID, T I);
template <typename T> bool readSubBlock(unsigned ID, T I);
// Read record data into the given Info data field, calling the appropriate
// parseRecord functions to parse and store the data.
template <typename T> llvm::Error readRecord(unsigned ID, T I);
template <typename T> bool readRecord(unsigned ID, T I);
// Allocate the relevant type of info and add read data to the object.
template <typename T>
llvm::Expected<std::unique_ptr<Info>> createInfo(unsigned ID);
template <typename T> std::unique_ptr<Info> createInfo(unsigned ID);
// Helper function to step through blocks to find and dispatch the next record
// or block to be read.
Cursor skipUntilRecordOrBlock(unsigned &BlockOrRecordID);
// Helper function to set up the approriate type of Info.
llvm::Expected<std::unique_ptr<Info>> readBlockToInfo(unsigned ID);
std::unique_ptr<Info> readBlockToInfo(unsigned ID);
llvm::BitstreamCursor &Stream;
Optional<llvm::BitstreamBlockInfo> BlockInfo;

View File

@@ -309,8 +309,10 @@ void ClangDocBitcodeWriter::emitRecord(const Location &Loc, RecordId ID) {
// FIXME: Assert that the line number is of the appropriate size.
Record.push_back(Loc.LineNumber);
assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize));
Record.push_back(Loc.Filename.size());
Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Loc.Filename);
// Record.push_back(Loc.Filename.size());
// Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Loc.Filename);
Record.push_back(4);
Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, "test");
}
void ClangDocBitcodeWriter::emitRecord(bool Val, RecordId ID) {
@@ -432,14 +434,6 @@ void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
emitBlock(N, FieldId::F_namespace);
for (const auto &CI : I.Description)
emitBlock(CI);
for (const auto &C : I.ChildNamespaces)
emitBlock(C, FieldId::F_child_namespace);
for (const auto &C : I.ChildRecords)
emitBlock(C, FieldId::F_child_record);
for (const auto &C : I.ChildFunctions)
emitBlock(C);
for (const auto &C : I.ChildEnums)
emitBlock(C);
}
void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
@@ -478,12 +472,6 @@ void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
emitBlock(P, FieldId::F_parent);
for (const auto &P : I.VirtualParents)
emitBlock(P, FieldId::F_vparent);
for (const auto &C : I.ChildRecords)
emitBlock(C, FieldId::F_child_record);
for (const auto &C : I.ChildFunctions)
emitBlock(C);
for (const auto &C : I.ChildEnums)
emitBlock(C);
}
void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {

View File

@@ -68,10 +68,11 @@ enum BlockId {
// New Ids need to be added to the enum here, and to the relevant IdNameMap and
// initialization list in the implementation file.
#define INFORECORDS(X) X##_USR, X##_NAME
enum RecordId {
VERSION = 1,
FUNCTION_USR,
FUNCTION_NAME,
INFORECORDS(FUNCTION),
FUNCTION_DEFLOCATION,
FUNCTION_LOCATION,
FUNCTION_ACCESS,
@@ -90,16 +91,13 @@ enum RecordId {
FIELD_TYPE_NAME,
MEMBER_TYPE_NAME,
MEMBER_TYPE_ACCESS,
NAMESPACE_USR,
NAMESPACE_NAME,
ENUM_USR,
ENUM_NAME,
INFORECORDS(NAMESPACE),
INFORECORDS(ENUM),
ENUM_DEFLOCATION,
ENUM_LOCATION,
ENUM_MEMBER,
ENUM_SCOPED,
RECORD_USR,
RECORD_NAME,
INFORECORDS(RECORD),
RECORD_DEFLOCATION,
RECORD_LOCATION,
RECORD_TAG_TYPE,
@@ -114,16 +112,10 @@ enum RecordId {
static constexpr unsigned BlockIdCount = BI_LAST - BI_FIRST;
static constexpr unsigned RecordIdCount = RI_LAST - RI_FIRST;
#undef INFORECORDS
// Identifiers for differentiating between subblocks
enum class FieldId {
F_default,
F_namespace,
F_parent,
F_vparent,
F_type,
F_child_namespace,
F_child_record
};
enum class FieldId { F_default, F_namespace, F_parent, F_vparent, F_type };
class ClangDocBitcodeWriter {
public:

View File

@@ -10,7 +10,6 @@ add_clang_library(clangDoc
ClangDoc.cpp
Generators.cpp
Mapper.cpp
MDGenerator.cpp
Representation.cpp
Serialize.cpp
YAMLGenerator.cpp

View File

@@ -29,11 +29,8 @@ findGeneratorByName(llvm::StringRef Format) {
// This anchor is used to force the linker to link in the generated object file
// and thus register the generators.
extern volatile int YAMLGeneratorAnchorSource;
extern volatile int MDGeneratorAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED YAMLGeneratorAnchorDest =
YAMLGeneratorAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED MDGeneratorAnchorDest =
MDGeneratorAnchorSource;
} // namespace doc
} // namespace clang

View File

@@ -27,7 +27,7 @@ public:
virtual ~Generator() = default;
// Write out the decl info in the specified format.
virtual llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) = 0;
virtual bool generateDocForInfo(Info *I, llvm::raw_ostream &OS) = 0;
};
typedef llvm::Registry<Generator> GeneratorRegistry;

View File

@@ -1,319 +0,0 @@
//===-- MDGenerator.cpp - Markdown Generator --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Generators.h"
#include "Representation.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include <string>
using namespace llvm;
namespace clang {
namespace doc {
// Enum conversion
std::string getAccess(AccessSpecifier AS) {
switch (AS) {
case AccessSpecifier::AS_public:
return "public";
case AccessSpecifier::AS_protected:
return "protected";
case AccessSpecifier::AS_private:
return "private";
case AccessSpecifier::AS_none:
return {};
}
llvm_unreachable("Unknown AccessSpecifier");
}
std::string getTagType(TagTypeKind AS) {
switch (AS) {
case TagTypeKind::TTK_Class:
return "class";
case TagTypeKind::TTK_Union:
return "union";
case TagTypeKind::TTK_Interface:
return "interface";
case TagTypeKind::TTK_Struct:
return "struct";
case TagTypeKind::TTK_Enum:
return "enum";
}
llvm_unreachable("Unknown TagTypeKind");
}
// Markdown generation
std::string genItalic(const Twine &Text) { return "*" + Text.str() + "*"; }
std::string genEmphasis(const Twine &Text) { return "**" + Text.str() + "**"; }
std::string genLink(const Twine &Text, const Twine &Link) {
return "[" + Text.str() + "](" + Link.str() + ")";
}
std::string genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {
std::string Buffer;
llvm::raw_string_ostream Stream(Buffer);
bool First = true;
for (const auto &R : Refs) {
if (!First)
Stream << ", ";
Stream << R.Name;
First = false;
}
return Stream.str();
}
void writeLine(const Twine &Text, raw_ostream &OS) { OS << Text << "\n\n"; }
void writeNewLine(raw_ostream &OS) { OS << "\n\n"; }
void writeHeader(const Twine &Text, unsigned int Num, raw_ostream &OS) {
OS << std::string(Num, '#') + " " + Text << "\n\n";
}
void writeFileDefinition(const Location &L, raw_ostream &OS) {
OS << genItalic("Defined at line " + std::to_string(L.LineNumber) + " of " +
L.Filename)
<< "\n\n";
}
void writeDescription(const CommentInfo &I, raw_ostream &OS) {
if (I.Kind == "FullComment") {
for (const auto &Child : I.Children)
writeDescription(*Child, OS);
} else if (I.Kind == "ParagraphComment") {
for (const auto &Child : I.Children)
writeDescription(*Child, OS);
writeNewLine(OS);
} else if (I.Kind == "BlockCommandComment") {
OS << genEmphasis(I.Name);
for (const auto &Child : I.Children)
writeDescription(*Child, OS);
} else if (I.Kind == "InlineCommandComment") {
OS << genEmphasis(I.Name) << " " << I.Text;
} else if (I.Kind == "ParamCommandComment") {
std::string Direction = I.Explicit ? (" " + I.Direction).str() : "";
OS << genEmphasis(I.ParamName) << I.Text << Direction << "\n\n";
} else if (I.Kind == "TParamCommandComment") {
std::string Direction = I.Explicit ? (" " + I.Direction).str() : "";
OS << genEmphasis(I.ParamName) << I.Text << Direction << "\n\n";
} else if (I.Kind == "VerbatimBlockComment") {
for (const auto &Child : I.Children)
writeDescription(*Child, OS);
} else if (I.Kind == "VerbatimBlockLineComment") {
OS << I.Text;
writeNewLine(OS);
} else if (I.Kind == "VerbatimLineComment") {
OS << I.Text;
writeNewLine(OS);
} else if (I.Kind == "HTMLStartTagComment") {
if (I.AttrKeys.size() != I.AttrValues.size())
return;
std::string Buffer;
llvm::raw_string_ostream Attrs(Buffer);
for (unsigned Idx = 0; Idx < I.AttrKeys.size(); ++Idx)
Attrs << " \"" << I.AttrKeys[Idx] << "=" << I.AttrValues[Idx] << "\"";
std::string CloseTag = I.SelfClosing ? "/>" : ">";
writeLine("<" + I.Name + Attrs.str() + CloseTag, OS);
} else if (I.Kind == "HTMLEndTagComment") {
writeLine("</" + I.Name + ">", OS);
} else if (I.Kind == "TextComment") {
OS << I.Text;
} else {
OS << "Unknown comment kind: " << I.Kind << ".\n\n";
}
}
void genMarkdown(const EnumInfo &I, llvm::raw_ostream &OS) {
if (I.Scoped)
writeLine("| enum class " + I.Name + " |", OS);
else
writeLine("| enum " + I.Name + " |", OS);
writeLine("--", OS);
std::string Buffer;
llvm::raw_string_ostream Members(Buffer);
if (!I.Members.empty())
for (const auto &N : I.Members)
Members << "| " << N << " |\n";
writeLine(Members.str(), OS);
if (I.DefLoc)
writeFileDefinition(I.DefLoc.getValue(), OS);
for (const auto &C : I.Description)
writeDescription(C, OS);
}
void genMarkdown(const FunctionInfo &I, llvm::raw_ostream &OS) {
std::string Buffer;
llvm::raw_string_ostream Stream(Buffer);
bool First = true;
for (const auto &N : I.Params) {
if (!First)
Stream << ", ";
Stream << N.Type.Name + " " + N.Name;
First = false;
}
writeHeader(I.Name, 3, OS);
std::string Access = getAccess(I.Access);
if (Access != "")
writeLine(genItalic(Access + " " + I.ReturnType.Type.Name + " " + I.Name +
"(" + Stream.str() + ")"),
OS);
else
writeLine(genItalic(I.ReturnType.Type.Name + " " + I.Name + "(" +
Stream.str() + ")"),
OS);
if (I.DefLoc)
writeFileDefinition(I.DefLoc.getValue(), OS);
for (const auto &C : I.Description)
writeDescription(C, OS);
}
void genMarkdown(const NamespaceInfo &I, llvm::raw_ostream &OS) {
if (I.Name == "")
writeHeader("Global Namespace", 1, OS);
else
writeHeader("namespace " + I.Name, 1, OS);
writeNewLine(OS);
if (!I.Description.empty()) {
for (const auto &C : I.Description)
writeDescription(C, OS);
writeNewLine(OS);
}
if (!I.ChildNamespaces.empty()) {
writeHeader("Namespaces", 2, OS);
for (const auto &R : I.ChildNamespaces)
writeLine(R.Name, OS);
writeNewLine(OS);
}
if (!I.ChildRecords.empty()) {
writeHeader("Records", 2, OS);
for (const auto &R : I.ChildRecords)
writeLine(R.Name, OS);
writeNewLine(OS);
}
if (!I.ChildFunctions.empty()) {
writeHeader("Functions", 2, OS);
for (const auto &F : I.ChildFunctions)
genMarkdown(F, OS);
writeNewLine(OS);
}
if (!I.ChildEnums.empty()) {
writeHeader("Enums", 2, OS);
for (const auto &E : I.ChildEnums)
genMarkdown(E, OS);
writeNewLine(OS);
}
}
void genMarkdown(const RecordInfo &I, llvm::raw_ostream &OS) {
writeHeader(getTagType(I.TagType) + " " + I.Name, 1, OS);
if (I.DefLoc)
writeFileDefinition(I.DefLoc.getValue(), OS);
if (!I.Description.empty()) {
for (const auto &C : I.Description)
writeDescription(C, OS);
writeNewLine(OS);
}
std::string Parents = genReferenceList(I.Parents);
std::string VParents = genReferenceList(I.VirtualParents);
if (!Parents.empty() || !VParents.empty()) {
if (Parents.empty())
writeLine("Inherits from " + VParents, OS);
else if (VParents.empty())
writeLine("Inherits from " + Parents, OS);
else
writeLine("Inherits from " + Parents + ", " + VParents, OS);
writeNewLine(OS);
}
if (!I.Members.empty()) {
writeHeader("Members", 2, OS);
for (const auto Member : I.Members) {
std::string Access = getAccess(Member.Access);
if (Access != "")
writeLine(Access + " " + Member.Type.Name + " " + Member.Name, OS);
else
writeLine(Member.Type.Name + " " + Member.Name, OS);
}
writeNewLine(OS);
}
if (!I.ChildRecords.empty()) {
writeHeader("Records", 2, OS);
for (const auto &R : I.ChildRecords)
writeLine(R.Name, OS);
writeNewLine(OS);
}
if (!I.ChildFunctions.empty()) {
writeHeader("Functions", 2, OS);
for (const auto &F : I.ChildFunctions)
genMarkdown(F, OS);
writeNewLine(OS);
}
if (!I.ChildEnums.empty()) {
writeHeader("Enums", 2, OS);
for (const auto &E : I.ChildEnums)
genMarkdown(E, OS);
writeNewLine(OS);
}
}
/// Generator for Markdown documentation.
class MDGenerator : public Generator {
public:
static const char *Format;
llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override;
};
const char *MDGenerator::Format = "md";
llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
switch (I->IT) {
case InfoType::IT_namespace:
genMarkdown(*static_cast<clang::doc::NamespaceInfo *>(I), OS);
break;
case InfoType::IT_record:
genMarkdown(*static_cast<clang::doc::RecordInfo *>(I), OS);
break;
case InfoType::IT_enum:
genMarkdown(*static_cast<clang::doc::EnumInfo *>(I), OS);
break;
case InfoType::IT_function:
genMarkdown(*static_cast<clang::doc::FunctionInfo *>(I), OS);
break;
case InfoType::IT_default:
return llvm::make_error<llvm::StringError>("Unexpected info type.\n",
llvm::inconvertibleErrorCode());
}
return llvm::Error::success();
}
static GeneratorRegistry::Add<MDGenerator> MD(MDGenerator::Format,
"Generator for MD output.");
// This anchor is used to force the linker to link in the generated object file
// and thus register the generator.
volatile int MDGeneratorAnchorSource = 0;
} // namespace doc
} // namespace clang

View File

@@ -13,7 +13,6 @@
#include "clang/AST/Comment.h"
#include "clang/Index/USRGeneration.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Error.h"
using clang::comments::FullComment;
@@ -29,24 +28,19 @@ template <typename T> bool MapASTVisitor::mapDecl(const T *D) {
if (D->getASTContext().getSourceManager().isInSystemHeader(D->getLocation()))
return true;
// Skip function-internal decls.
if (D->getParentFunctionOrMethod())
return true;
llvm::SmallString<128> USR;
// If there is an error generating a USR for the decl, skip this decl.
if (index::generateUSRForDecl(D, USR))
return true;
auto I = serialize::emitInfo(
std::string info = serialize::emitInfo(
D, getComment(D, D->getASTContext()), getLine(D, D->getASTContext()),
getFile(D, D->getASTContext()), CDCtx.PublicOnly);
// A null in place of I indicates that the serializer is skipping this decl
// for some reason (e.g. we're only reporting public decls).
if (I)
CDCtx.ECtx->reportResult(llvm::toHex(llvm::toStringRef(I->USR)),
serialize::serialize(I));
if (info != "")
CDCtx.ECtx->reportResult(
llvm::toHex(llvm::toStringRef(serialize::hashUSR(USR))), info);
return true;
}
@@ -82,13 +76,13 @@ MapASTVisitor::getComment(const NamedDecl *D, const ASTContext &Context) const {
int MapASTVisitor::getLine(const NamedDecl *D,
const ASTContext &Context) const {
return Context.getSourceManager().getPresumedLoc(D->getBeginLoc()).getLine();
return Context.getSourceManager().getPresumedLoc(D->getLocStart()).getLine();
}
llvm::StringRef MapASTVisitor::getFile(const NamedDecl *D,
const ASTContext &Context) const {
return Context.getSourceManager()
.getPresumedLoc(D->getBeginLoc())
.getPresumedLoc(D->getLocStart())
.getFilename();
}

View File

@@ -26,70 +26,17 @@
namespace clang {
namespace doc {
namespace {
const SymbolID EmptySID = SymbolID();
static const SymbolID EmptySID = SymbolID();
template <typename T>
llvm::Expected<std::unique_ptr<Info>>
reduce(std::vector<std::unique_ptr<Info>> &Values) {
if (Values.empty())
return llvm::make_error<llvm::StringError>(" No values to reduce.\n",
llvm::inconvertibleErrorCode());
std::unique_ptr<Info> Merged = llvm::make_unique<T>(Values[0]->USR);
std::unique_ptr<Info> reduce(std::vector<std::unique_ptr<Info>> &Values) {
std::unique_ptr<Info> Merged = llvm::make_unique<T>();
T *Tmp = static_cast<T *>(Merged.get());
for (auto &I : Values)
Tmp->merge(std::move(*static_cast<T *>(I.get())));
return std::move(Merged);
return Merged;
}
// Return the index of the matching child in the vector, or -1 if merge is not
// necessary.
template <typename T>
int getChildIndexIfExists(std::vector<T> &Children, T &ChildToMerge) {
for (unsigned long I = 0; I < Children.size(); I++) {
if (ChildToMerge.USR == Children[I].USR)
return I;
}
return -1;
}
// For References, we don't need to actually merge them, we just don't want
// duplicates.
void reduceChildren(std::vector<Reference> &Children,
std::vector<Reference> &&ChildrenToMerge) {
for (auto &ChildToMerge : ChildrenToMerge) {
if (getChildIndexIfExists(Children, ChildToMerge) == -1)
Children.push_back(std::move(ChildToMerge));
}
}
void reduceChildren(std::vector<FunctionInfo> &Children,
std::vector<FunctionInfo> &&ChildrenToMerge) {
for (auto &ChildToMerge : ChildrenToMerge) {
int mergeIdx = getChildIndexIfExists(Children, ChildToMerge);
if (mergeIdx == -1) {
Children.push_back(std::move(ChildToMerge));
continue;
}
Children[mergeIdx].merge(std::move(ChildToMerge));
}
}
void reduceChildren(std::vector<EnumInfo> &Children,
std::vector<EnumInfo> &&ChildrenToMerge) {
for (auto &ChildToMerge : ChildrenToMerge) {
int mergeIdx = getChildIndexIfExists(Children, ChildToMerge);
if (mergeIdx == -1) {
Children.push_back(std::move(ChildToMerge));
continue;
}
Children[mergeIdx].merge(std::move(ChildToMerge));
}
}
} // namespace
// Dispatch function.
llvm::Expected<std::unique_ptr<Info>>
mergeInfos(std::vector<std::unique_ptr<Info>> &Values) {
@@ -126,7 +73,7 @@ void Info::mergeBase(Info &&Other) {
}
bool Info::mergeable(const Info &Other) {
return IT == Other.IT && USR == Other.USR;
return IT == Other.IT && (USR == EmptySID || USR == Other.USR);
}
void SymbolInfo::merge(SymbolInfo &&Other) {
@@ -140,11 +87,6 @@ void SymbolInfo::merge(SymbolInfo &&Other) {
void NamespaceInfo::merge(NamespaceInfo &&Other) {
assert(mergeable(Other));
// Reduce children if necessary.
reduceChildren(ChildNamespaces, std::move(Other.ChildNamespaces));
reduceChildren(ChildRecords, std::move(Other.ChildRecords));
reduceChildren(ChildFunctions, std::move(Other.ChildFunctions));
reduceChildren(ChildEnums, std::move(Other.ChildEnums));
mergeBase(std::move(Other));
}
@@ -158,10 +100,6 @@ void RecordInfo::merge(RecordInfo &&Other) {
Parents = std::move(Other.Parents);
if (VirtualParents.empty())
VirtualParents = std::move(Other.VirtualParents);
// Reduce children if necessary.
reduceChildren(ChildRecords, std::move(Other.ChildRecords));
reduceChildren(ChildFunctions, std::move(Other.ChildFunctions));
reduceChildren(ChildEnums, std::move(Other.ChildEnums));
SymbolInfo::merge(std::move(Other));
}

View File

@@ -31,9 +31,6 @@ namespace doc {
using SymbolID = std::array<uint8_t, 20>;
struct Info;
struct FunctionInfo;
struct EnumInfo;
enum class InfoType {
IT_default,
IT_namespace,
@@ -48,14 +45,13 @@ struct CommentInfo {
CommentInfo(CommentInfo &Other) = delete;
CommentInfo(CommentInfo &&Other) = default;
SmallString<16>
Kind; // Kind of comment (FullComment, ParagraphComment, TextComment,
// InlineCommandComment, HTMLStartTagComment, HTMLEndTagComment,
// BlockCommandComment, ParamCommandComment,
// TParamCommandComment, VerbatimBlockComment,
// VerbatimBlockLineComment, VerbatimLineComment).
SmallString<64> Text; // Text of the comment.
SmallString<16> Name; // Name of the comment (for Verbatim and HTML).
SmallString<16> Kind; // Kind of comment (TextComment, InlineCommandComment,
// HTMLStartTagComment, HTMLEndTagComment,
// BlockCommandComment, ParamCommandComment,
// TParamCommandComment, VerbatimBlockComment,
// VerbatimBlockLineComment, VerbatimLineComment).
SmallString<64> Text; // Text of the comment.
SmallString<16> Name; // Name of the comment (for Verbatim and HTML).
SmallString<8> Direction; // Parameter direction (for (T)ParamCommand).
SmallString<16> ParamName; // Parameter name (for (T)ParamCommand).
SmallString<16> CloseName; // Closing tag name (for VerbatimBlock).
@@ -157,14 +153,9 @@ struct Location {
struct Info {
Info() = default;
Info(InfoType IT) : IT(IT) {}
Info(InfoType IT, SymbolID USR) : USR(USR), IT(IT) {}
Info(InfoType IT, SymbolID USR, StringRef Name)
: USR(USR), IT(IT), Name(Name) {}
Info(const Info &Other) = delete;
Info(Info &&Other) = default;
virtual ~Info() = default;
SymbolID USR =
SymbolID(); // Unique identifier for the decl described by this Info.
const InfoType IT = InfoType::IT_default; // InfoType of this particular Info.
@@ -175,36 +166,18 @@ struct Info {
void mergeBase(Info &&I);
bool mergeable(const Info &Other);
// Returns a reference to the parent scope (that is, the immediate parent
// namespace or class in which this decl resides).
llvm::Expected<Reference> getEnclosingScope();
};
// Info for namespaces.
struct NamespaceInfo : public Info {
NamespaceInfo() : Info(InfoType::IT_namespace) {}
NamespaceInfo(SymbolID USR) : Info(InfoType::IT_namespace, USR) {}
NamespaceInfo(SymbolID USR, StringRef Name)
: Info(InfoType::IT_namespace, USR, Name) {}
void merge(NamespaceInfo &&I);
// Namespaces and Records are references because they will be properly
// documented in their own info, while the entirety of Functions and Enums are
// included here because they should not have separate documentation from
// their scope.
std::vector<Reference> ChildNamespaces;
std::vector<Reference> ChildRecords;
std::vector<FunctionInfo> ChildFunctions;
std::vector<EnumInfo> ChildEnums;
};
// Info for symbols.
struct SymbolInfo : public Info {
SymbolInfo(InfoType IT) : Info(IT) {}
SymbolInfo(InfoType IT, SymbolID USR) : Info(IT, USR) {}
SymbolInfo(InfoType IT, SymbolID USR, StringRef Name) : Info(IT, USR, Name) {}
void merge(SymbolInfo &&I);
@@ -216,7 +189,6 @@ struct SymbolInfo : public Info {
// Info for functions.
struct FunctionInfo : public SymbolInfo {
FunctionInfo() : SymbolInfo(InfoType::IT_function) {}
FunctionInfo(SymbolID USR) : SymbolInfo(InfoType::IT_function, USR) {}
void merge(FunctionInfo &&I);
@@ -233,9 +205,6 @@ struct FunctionInfo : public SymbolInfo {
// Info for types.
struct RecordInfo : public SymbolInfo {
RecordInfo() : SymbolInfo(InfoType::IT_record) {}
RecordInfo(SymbolID USR) : SymbolInfo(InfoType::IT_record, USR) {}
RecordInfo(SymbolID USR, StringRef Name)
: SymbolInfo(InfoType::IT_record, USR, Name) {}
void merge(RecordInfo &&I);
@@ -249,21 +218,12 @@ struct RecordInfo : public SymbolInfo {
// parents).
llvm::SmallVector<Reference, 4>
VirtualParents; // List of virtual base/parent records.
// Records are references because they will be properly
// documented in their own info, while the entirety of Functions and Enums are
// included here because they should not have separate documentation from
// their scope.
std::vector<Reference> ChildRecords;
std::vector<FunctionInfo> ChildFunctions;
std::vector<EnumInfo> ChildEnums;
};
// TODO: Expand to allow for documenting templating.
// Info for types.
struct EnumInfo : public SymbolInfo {
EnumInfo() : SymbolInfo(InfoType::IT_enum) {}
EnumInfo(SymbolID USR) : SymbolInfo(InfoType::IT_enum, USR) {}
void merge(EnumInfo &&I);

View File

@@ -152,21 +152,6 @@ template <typename T> static std::string serialize(T &I) {
return Buffer.str().str();
}
std::string serialize(std::unique_ptr<Info> &I) {
switch (I->IT) {
case InfoType::IT_namespace:
return serialize(*static_cast<NamespaceInfo *>(I.get()));
case InfoType::IT_record:
return serialize(*static_cast<RecordInfo *>(I.get()));
case InfoType::IT_enum:
return serialize(*static_cast<EnumInfo *>(I.get()));
case InfoType::IT_function:
return serialize(*static_cast<FunctionInfo *>(I.get()));
default:
return "";
}
}
static void parseFullComment(const FullComment *C, CommentInfo &CI) {
ClangDocCommentVisitor Visitor(CI);
Visitor.parseComment(C);
@@ -244,9 +229,6 @@ static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
}
static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
// Don't parse bases if this isn't a definition.
if (!D->isThisDeclarationADefinition())
return;
for (const CXXBaseSpecifier &B : D->bases()) {
if (B.isVirtual())
continue;
@@ -324,106 +306,61 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
parseParameters(I, D);
}
std::unique_ptr<Info> emitInfo(const NamespaceDecl *D, const FullComment *FC,
int LineNumber, llvm::StringRef File,
bool PublicOnly) {
std::string emitInfo(const NamespaceDecl *D, const FullComment *FC,
int LineNumber, llvm::StringRef File, bool PublicOnly) {
if (PublicOnly && ((D->isAnonymousNamespace()) ||
!isPublic(D->getAccess(), D->getLinkageInternal())))
return nullptr;
auto I = llvm::make_unique<NamespaceInfo>();
populateInfo(*I, D, FC);
return std::unique_ptr<Info>{std::move(I)};
return "";
NamespaceInfo I;
populateInfo(I, D, FC);
return serialize(I);
}
std::unique_ptr<Info> emitInfo(const RecordDecl *D, const FullComment *FC,
int LineNumber, llvm::StringRef File,
bool PublicOnly) {
std::string emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
llvm::StringRef File, bool PublicOnly) {
if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
return nullptr;
auto I = llvm::make_unique<RecordInfo>();
populateSymbolInfo(*I, D, FC, LineNumber, File);
I->TagType = D->getTagKind();
parseFields(*I, D, PublicOnly);
return "";
RecordInfo I;
populateSymbolInfo(I, D, FC, LineNumber, File);
I.TagType = D->getTagKind();
parseFields(I, D, PublicOnly);
if (const auto *C = dyn_cast<CXXRecordDecl>(D))
parseBases(*I, C);
return std::unique_ptr<Info>{std::move(I)};
parseBases(I, C);
return serialize(I);
}
std::unique_ptr<Info> emitInfo(const FunctionDecl *D, const FullComment *FC,
int LineNumber, llvm::StringRef File,
bool PublicOnly) {
std::string emitInfo(const FunctionDecl *D, const FullComment *FC,
int LineNumber, llvm::StringRef File, bool PublicOnly) {
if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
return nullptr;
FunctionInfo Func;
populateFunctionInfo(Func, D, FC, LineNumber, File);
Func.Access = clang::AccessSpecifier::AS_none;
// Wrap in enclosing scope
auto I = llvm::make_unique<NamespaceInfo>();
if (!Func.Namespace.empty())
I->USR = Func.Namespace[0].USR;
else
I->USR = SymbolID();
I->ChildFunctions.emplace_back(std::move(Func));
return std::unique_ptr<Info>{std::move(I)};
return "";
FunctionInfo I;
populateFunctionInfo(I, D, FC, LineNumber, File);
I.Access = clang::AccessSpecifier::AS_none;
return serialize(I);
}
std::unique_ptr<Info> emitInfo(const CXXMethodDecl *D, const FullComment *FC,
int LineNumber, llvm::StringRef File,
bool PublicOnly) {
std::string emitInfo(const CXXMethodDecl *D, const FullComment *FC,
int LineNumber, llvm::StringRef File, bool PublicOnly) {
if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
return nullptr;
FunctionInfo Func;
populateFunctionInfo(Func, D, FC, LineNumber, File);
Func.IsMethod = true;
SymbolID ParentUSR = getUSRForDecl(D->getParent());
Func.Parent = Reference{ParentUSR, D->getParent()->getNameAsString(),
InfoType::IT_record};
Func.Access = D->getAccess();
// Wrap in enclosing scope
auto I = llvm::make_unique<RecordInfo>();
I->USR = ParentUSR;
I->ChildFunctions.emplace_back(std::move(Func));
return std::unique_ptr<Info>{std::move(I)};
return "";
FunctionInfo I;
populateFunctionInfo(I, D, FC, LineNumber, File);
I.IsMethod = true;
I.Parent = Reference{getUSRForDecl(D->getParent()),
D->getParent()->getNameAsString(), InfoType::IT_record};
I.Access = D->getAccess();
return serialize(I);
}
std::unique_ptr<Info> emitInfo(const EnumDecl *D, const FullComment *FC,
int LineNumber, llvm::StringRef File,
bool PublicOnly) {
std::string emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
llvm::StringRef File, bool PublicOnly) {
if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
return nullptr;
EnumInfo Enum;
populateSymbolInfo(Enum, D, FC, LineNumber, File);
Enum.Scoped = D->isScoped();
parseEnumerators(Enum, D);
// Wrap in enclosing scope
if (!Enum.Namespace.empty()) {
switch (Enum.Namespace[0].RefType) {
case InfoType::IT_namespace: {
auto I = llvm::make_unique<NamespaceInfo>();
I->USR = Enum.Namespace[0].USR;
I->ChildEnums.emplace_back(std::move(Enum));
return std::unique_ptr<Info>{std::move(I)};
}
case InfoType::IT_record: {
auto I = llvm::make_unique<RecordInfo>();
I->USR = Enum.Namespace[0].USR;
I->ChildEnums.emplace_back(std::move(Enum));
return std::unique_ptr<Info>{std::move(I)};
}
default:
break;
}
}
// Put in global namespace
auto I = llvm::make_unique<NamespaceInfo>();
I->USR = SymbolID();
I->ChildEnums.emplace_back(std::move(Enum));
return std::unique_ptr<Info>{std::move(I)};
return "";
EnumInfo I;
populateSymbolInfo(I, D, FC, LineNumber, File);
I.Scoped = D->isScoped();
parseEnumerators(I, D);
return serialize(I);
}
} // namespace serialize

View File

@@ -28,16 +28,16 @@ namespace clang {
namespace doc {
namespace serialize {
std::unique_ptr<Info> emitInfo(const NamespaceDecl *D, const FullComment *FC,
int LineNumber, StringRef File, bool PublicOnly);
std::unique_ptr<Info> emitInfo(const RecordDecl *D, const FullComment *FC,
int LineNumber, StringRef File, bool PublicOnly);
std::unique_ptr<Info> emitInfo(const EnumDecl *D, const FullComment *FC,
int LineNumber, StringRef File, bool PublicOnly);
std::unique_ptr<Info> emitInfo(const FunctionDecl *D, const FullComment *FC,
int LineNumber, StringRef File, bool PublicOnly);
std::unique_ptr<Info> emitInfo(const CXXMethodDecl *D, const FullComment *FC,
int LineNumber, StringRef File, bool PublicOnly);
std::string emitInfo(const NamespaceDecl *D, const FullComment *FC,
int LineNumber, StringRef File, bool PublicOnly);
std::string emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
StringRef File, bool PublicOnly);
std::string emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
StringRef File, bool PublicOnly);
std::string emitInfo(const FunctionDecl *D, const FullComment *FC,
int LineNumber, StringRef File, bool PublicOnly);
std::string emitInfo(const CXXMethodDecl *D, const FullComment *FC,
int LineNumber, StringRef File, bool PublicOnly);
// Function to hash a given USR value for storage.
// As USRs (Unified Symbol Resolution) could be large, especially for functions
@@ -46,8 +46,6 @@ std::unique_ptr<Info> emitInfo(const CXXMethodDecl *D, const FullComment *FC,
// memory (vs storing USRs directly).
SymbolID hashUSR(llvm::StringRef USR);
std::string serialize(std::unique_ptr<Info> &I);
} // namespace serialize
} // namespace doc
} // namespace clang

View File

@@ -20,8 +20,6 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(MemberTypeInfo)
LLVM_YAML_IS_SEQUENCE_VECTOR(Reference)
LLVM_YAML_IS_SEQUENCE_VECTOR(Location)
LLVM_YAML_IS_SEQUENCE_VECTOR(CommentInfo)
LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionInfo)
LLVM_YAML_IS_SEQUENCE_VECTOR(EnumInfo)
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<CommentInfo>)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::SmallString<16>)
@@ -177,14 +175,7 @@ template <> struct MappingTraits<MemberTypeInfo> {
};
template <> struct MappingTraits<NamespaceInfo> {
static void mapping(IO &IO, NamespaceInfo &I) {
InfoMapping(IO, I);
IO.mapOptional("ChildNamespaces", I.ChildNamespaces,
std::vector<Reference>());
IO.mapOptional("ChildRecords", I.ChildRecords, std::vector<Reference>());
IO.mapOptional("ChildFunctions", I.ChildFunctions);
IO.mapOptional("ChildEnums", I.ChildEnums);
}
static void mapping(IO &IO, NamespaceInfo &I) { InfoMapping(IO, I); }
};
template <> struct MappingTraits<RecordInfo> {
@@ -195,9 +186,6 @@ template <> struct MappingTraits<RecordInfo> {
IO.mapOptional("Parents", I.Parents, llvm::SmallVector<Reference, 4>());
IO.mapOptional("VirtualParents", I.VirtualParents,
llvm::SmallVector<Reference, 4>());
IO.mapOptional("ChildRecords", I.ChildRecords, std::vector<Reference>());
IO.mapOptional("ChildFunctions", I.ChildFunctions);
IO.mapOptional("ChildEnums", I.ChildEnums);
}
};
@@ -242,12 +230,12 @@ class YAMLGenerator : public Generator {
public:
static const char *Format;
llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override;
bool generateDocForInfo(Info *I, llvm::raw_ostream &OS) override;
};
const char *YAMLGenerator::Format = "yaml";
llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
bool YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
llvm::yaml::Output InfoYAML(OS);
switch (I->IT) {
case InfoType::IT_namespace:
@@ -263,10 +251,10 @@ llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
InfoYAML << *static_cast<clang::doc::FunctionInfo *>(I);
break;
case InfoType::IT_default:
return llvm::make_error<llvm::StringError>("Unexpected info type.\n",
llvm::inconvertibleErrorCode());
llvm::errs() << "Unexpected info type in index.\n";
return true;
}
return llvm::Error::success();
return false;
}
static GeneratorRegistry::Add<YAMLGenerator> YAML(YAMLGenerator::Format,

View File

@@ -0,0 +1,200 @@
#!/usr/bin/env python3
#
#===- gen_tests.py - clang-doc test generator ----------------*- python -*--===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
"""
clang-doc test generator
==========================
Generates tests for clang-doc given a certain set of flags, a prefix for the
test file, and a given clang-doc binary. Please check emitted tests for
accuracy before using.
To generate all current tests:
- Generate mapper tests:
gen_tests.py -flag='--dump-mapper' -flag='--doxygen' -prefix mapper
- Generate reducer tests:
gen_tests.py -flag='--dump-intermediate' -flag='--doxygen' -prefix bc
- Generate yaml tests:
gen_tests.py -flag='--format=yaml' -flag='--doxygen' -prefix yaml
This script was written on/for Linux, and has not been tested on any other
platform and so it may not work.
"""
import argparse
import glob
import os
import shutil
import subprocess
RUN_CLANG_DOC = """
// RUN: clang-doc {0} -p %t %t/test.cpp -output=%t/docs
"""
RUN = """
// RUN: {0} %t/{1} | FileCheck %s --check-prefix CHECK-{2}
"""
CHECK = '// CHECK-{0}: '
CHECK_NEXT = '// CHECK-{0}-NEXT: '
def clear_test_prefix_files(prefix, tests_path):
if os.path.isdir(tests_path):
for root, dirs, files in os.walk(tests_path):
for filename in files:
if filename.startswith(prefix):
os.remove(os.path.join(root, filename))
def copy_to_test_file(test_case_path, test_cases_path):
# Copy file to 'test.cpp' to preserve file-dependent USRs
test_file = os.path.join(test_cases_path, 'test.cpp')
shutil.copyfile(test_case_path, test_file)
return test_file
def run_clang_doc(args, out_dir, test_file):
# Run clang-doc.
current_cmd = [args.clangdoc]
current_cmd.extend(args.flags)
current_cmd.append('--output=' + out_dir)
current_cmd.append(test_file)
print('Running ' + ' '.join(current_cmd))
return_code = subprocess.call(current_cmd)
if return_code:
return 1
return 0
def get_test_case_code(test_case_path, flags):
# Get the test case code
code = ''
with open(test_case_path, 'r') as code_file:
code = code_file.read()
code += RUN_CLANG_DOC.format(flags)
return code
def get_output(root, out_file, case_out_path, flags, checkname, bcanalyzer):
output = ''
run_cmd = ''
if '--dump-mapper' in flags or '--dump-intermediate' in flags:
# Run llvm-bcanalyzer
output = subprocess.check_output(
[bcanalyzer, '--dump',
os.path.join(root, out_file)])
output = output[:output.find('Summary of ')].rstrip()
run_cmd = RUN.format('llvm-bcanalyzer --dump',
os.path.join('docs', 'bc', out_file), checkname)
else:
# Run cat
output = subprocess.check_output(['cat', os.path.join(root, out_file)])
run_cmd = RUN.format(
'cat',
os.path.join('docs', os.path.relpath(root, case_out_path),
out_file), checkname)
# Format output.
output = output.replace('blob data = \'test\'', 'blob data = \'{{.*}}\'')
output = CHECK.format(checkname) + output.rstrip()
output = run_cmd + output.replace('\n',
'\n' + CHECK_NEXT.format(checkname))
return output + '\n'
def main():
parser = argparse.ArgumentParser(description='Generate clang-doc tests.')
parser.add_argument(
'-flag',
action='append',
default=[],
dest='flags',
help='Flags to pass to clang-doc.')
parser.add_argument(
'-prefix',
type=str,
default='',
dest='prefix',
help='Prefix for this test group.')
parser.add_argument(
'-clang-doc-binary',
dest='clangdoc',
metavar="PATH",
default='clang-doc',
help='path to clang-doc binary')
parser.add_argument(
'-llvm-bcanalyzer-binary',
dest='bcanalyzer',
metavar="PATH",
default='llvm-bcanalyzer',
help='path to llvm-bcanalyzer binary')
args = parser.parse_args()
flags = ' '.join(args.flags)
clang_doc_path = os.path.dirname(__file__)
tests_path = os.path.join(clang_doc_path, '..', 'test', 'clang-doc')
test_cases_path = os.path.join(tests_path, 'test_cases')
clear_test_prefix_files(args.prefix, tests_path)
for test_case_path in glob.glob(os.path.join(test_cases_path, '*')):
if test_case_path.endswith(
'compile_flags.txt') or test_case_path.endswith(
'compile_commands.json'):
continue
# Name of this test case
case_name = os.path.basename(test_case_path).split('.')[0]
test_file = copy_to_test_file(test_case_path, test_cases_path)
out_dir = os.path.join(test_cases_path, case_name)
if run_clang_doc(args, out_dir, test_file):
return 1
# Retrieve output and format as FileCheck tests
all_output = ''
num_outputs = 0
for root, dirs, files in os.walk(out_dir):
for out_file in files:
# Make the file check the first 3 letters (there's a very small chance
# that this will collide, but the fix is to simply change the decl name)
usr = os.path.basename(out_file).split('.')
# If the usr is less than 2, this isn't one of the test files.
if len(usr) < 2:
continue
all_output += get_output(root, out_file, out_dir, args.flags,
num_outputs, args.bcanalyzer)
num_outputs += 1
# Add test case code to test
all_output = get_test_case_code(test_case_path,
flags) + '\n' + all_output
# Write to test case file in /test.
test_out_path = os.path.join(
tests_path, args.prefix + '-' + os.path.basename(test_case_path))
with open(test_out_path, 'w+') as o:
o.write(all_output)
# Clean up
shutil.rmtree(out_dir)
os.remove(test_file)
if __name__ == '__main__':
main()

View File

@@ -31,9 +31,9 @@
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Execution.h"
#include "clang/Tooling/StandaloneExecution.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
@@ -54,39 +54,34 @@ static llvm::cl::opt<std::string>
llvm::cl::desc("Directory for outputting generated files."),
llvm::cl::init("docs"), llvm::cl::cat(ClangDocCategory));
static llvm::cl::opt<bool>
DumpMapperResult("dump-mapper",
llvm::cl::desc("Dump mapper results to bitcode file."),
llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
static llvm::cl::opt<bool> DumpIntermediateResult(
"dump-intermediate",
llvm::cl::desc("Dump intermediate results to bitcode file."),
llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
static llvm::cl::opt<bool>
PublicOnly("public", llvm::cl::desc("Document only public declarations."),
llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
enum OutputFormatTy {
yaml,
};
static llvm::cl::opt<OutputFormatTy> FormatEnum(
"format", llvm::cl::desc("Format for outputted docs."),
llvm::cl::values(clEnumVal(yaml, "Documentation in YAML format.")),
llvm::cl::init(yaml), llvm::cl::cat(ClangDocCategory));
static llvm::cl::opt<bool> DoxygenOnly(
"doxygen",
llvm::cl::desc("Use only doxygen-style comments to generate docs."),
llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
enum OutputFormatTy {
md,
yaml,
};
static llvm::cl::opt<OutputFormatTy>
FormatEnum("format", llvm::cl::desc("Format for outputted docs."),
llvm::cl::values(clEnumValN(OutputFormatTy::yaml, "yaml",
"Documentation in YAML format."),
clEnumValN(OutputFormatTy::md, "md",
"Documentation in MD format.")),
llvm::cl::init(OutputFormatTy::yaml),
llvm::cl::cat(ClangDocCategory));
std::string getFormatString() {
switch (FormatEnum) {
case OutputFormatTy::yaml:
return "yaml";
case OutputFormatTy::md:
return "md";
}
llvm_unreachable("Unknown OutputFormatTy");
}
bool CreateDirectory(const Twine &DirName, bool ClearDirectory = false) {
std::error_code OK;
llvm::SmallString<128> DocsRootPath;
@@ -106,24 +101,29 @@ bool CreateDirectory(const Twine &DirName, bool ClearDirectory = false) {
return false;
}
// A function to extract the appropriate path name for a given info's
// documentation. The path returned is a composite of the parent namespaces as
// directories plus the decl name as the filename.
//
// Example: Given the below, the <ext> path for class C will be <
// root>/A/B/C.<ext>
//
// namespace A {
// namesapce B {
//
// class C {};
//
// }
// }
bool DumpResultToFile(const Twine &DirName, const Twine &FileName,
StringRef Buffer, bool ClearDirectory = false) {
std::error_code OK;
llvm::SmallString<128> IRRootPath;
llvm::sys::path::native(OutDirectory, IRRootPath);
llvm::sys::path::append(IRRootPath, DirName);
if (CreateDirectory(IRRootPath, ClearDirectory))
return true;
llvm::sys::path::append(IRRootPath, FileName);
std::error_code OutErrorInfo;
llvm::raw_fd_ostream OS(IRRootPath, OutErrorInfo, llvm::sys::fs::F_None);
if (OutErrorInfo != OK) {
llvm::errs() << "Error opening documentation file.\n";
return true;
}
OS << Buffer;
OS.close();
return false;
}
llvm::Expected<llvm::SmallString<128>>
getInfoOutputFile(StringRef Root,
llvm::SmallVectorImpl<doc::Reference> &Namespaces,
StringRef Name, StringRef Ext) {
getPath(StringRef Root, StringRef Ext, StringRef Name,
llvm::SmallVectorImpl<doc::Reference> &Namespaces) {
std::error_code OK;
llvm::SmallString<128> Path;
llvm::sys::path::native(Root, Path);
@@ -134,41 +134,30 @@ getInfoOutputFile(StringRef Root,
return llvm::make_error<llvm::StringError>("Unable to create directory.\n",
llvm::inconvertibleErrorCode());
if (Name.empty())
Name = "GlobalNamespace";
llvm::sys::path::append(Path, Name + Ext);
return Path;
}
// Iterate through tool results and build string map of info vectors from the
// encoded bitstreams.
bool bitcodeResultsToInfos(
tooling::ToolResults &Results,
llvm::StringMap<std::vector<std::unique_ptr<doc::Info>>> &Output) {
bool Err = false;
Results.forEachResult([&](StringRef Key, StringRef Value) {
llvm::BitstreamCursor Stream(Value);
doc::ClangDocBitcodeReader Reader(Stream);
auto Infos = Reader.readBitcode();
if (!Infos) {
llvm::errs() << toString(Infos.takeError()) << "\n";
Err = true;
return;
}
for (auto &I : Infos.get()) {
auto R =
Output.try_emplace(Key, std::vector<std::unique_ptr<doc::Info>>());
R.first->second.emplace_back(std::move(I));
}
});
return Err;
std::string getFormatString(OutputFormatTy Ty) {
switch (Ty) {
case yaml:
return "yaml";
}
llvm_unreachable("Unknown OutputFormatTy");
}
int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
std::error_code OK;
ExecutorName.setInitialValue("all-TUs");
// Fail early if an invalid format was provided.
std::string Format = getFormatString(FormatEnum);
auto G = doc::findGeneratorByName(Format);
if (!G) {
llvm::errs() << toString(G.takeError()) << "\n";
return 1;
}
auto Exec = clang::tooling::createExecutorFromCommandLineArgs(
argc, argv, ClangDocCategory);
@@ -177,15 +166,6 @@ int main(int argc, const char **argv) {
return 1;
}
// Fail early if an invalid format was provided.
std::string Format = getFormatString();
llvm::outs() << "Emiting docs in " << Format << " format.\n";
auto G = doc::findGeneratorByName(Format);
if (!G) {
llvm::errs() << toString(G.takeError()) << "\n";
return 1;
}
ArgumentsAdjuster ArgAdjuster;
if (!DoxygenOnly)
ArgAdjuster = combineAdjusters(
@@ -204,27 +184,56 @@ int main(int argc, const char **argv) {
return 1;
}
if (DumpMapperResult) {
bool Err = false;
Exec->get()->getToolResults()->forEachResult(
[&](StringRef Key, StringRef Value) {
Err = DumpResultToFile("bc", Key + ".bc", Value);
});
if (Err)
llvm::errs() << "Error dumping map results.\n";
return Err;
}
// Collect values into output by key.
llvm::outs() << "Collecting infos...\n";
llvm::StringMap<std::vector<std::unique_ptr<doc::Info>>> MapOutput;
// In ToolResults, the Key is the hashed USR and the value is the
// bitcode-encoded representation of the Info object.
llvm::outs() << "Collecting infos...\n";
llvm::StringMap<std::vector<std::unique_ptr<doc::Info>>> USRToInfos;
if (bitcodeResultsToInfos(*Exec->get()->getToolResults(), USRToInfos))
return 1;
Exec->get()->getToolResults()->forEachResult([&](StringRef Key,
StringRef Value) {
llvm::BitstreamCursor Stream(Value);
doc::ClangDocBitcodeReader Reader(Stream);
auto Infos = Reader.readBitcode();
for (auto &I : Infos) {
auto R =
MapOutput.try_emplace(Key, std::vector<std::unique_ptr<doc::Info>>());
R.first->second.emplace_back(std::move(I));
}
});
// First reducing phase (reduce all decls into one info per decl).
llvm::outs() << "Reducing " << USRToInfos.size() << " infos...\n";
for (auto &Group : USRToInfos) {
// Reducing and generation phases
llvm::outs() << "Reducing " << MapOutput.size() << " infos...\n";
llvm::StringMap<std::unique_ptr<doc::Info>> ReduceOutput;
for (auto &Group : MapOutput) {
auto Reduced = doc::mergeInfos(Group.getValue());
if (!Reduced) {
if (!Reduced)
llvm::errs() << llvm::toString(Reduced.takeError());
if (DumpIntermediateResult) {
SmallString<4096> Buffer;
llvm::BitstreamWriter Stream(Buffer);
doc::ClangDocBitcodeWriter Writer(Stream);
Writer.dispatchInfoForWrite(Reduced.get().get());
if (DumpResultToFile("bc", Group.getKey() + ".bc", Buffer))
llvm::errs() << "Error dumping to bitcode.\n";
continue;
}
// Create the relevant ostream and emit the documentation for this decl.
doc::Info *I = Reduced.get().get();
auto InfoPath =
getInfoOutputFile(OutDirectory, I->Namespace, I->Name, "." + Format);
auto InfoPath = getPath(OutDirectory, "." + Format, I->Name, I->Namespace);
if (!InfoPath) {
llvm::errs() << toString(InfoPath.takeError()) << "\n";
continue;
@@ -232,12 +241,12 @@ int main(int argc, const char **argv) {
std::error_code FileErr;
llvm::raw_fd_ostream InfoOS(InfoPath.get(), FileErr, llvm::sys::fs::F_None);
if (FileErr != OK) {
llvm::errs() << "Error opening info file: " << FileErr.message() << "\n";
llvm::errs() << "Error opening index file: " << FileErr.message() << "\n";
continue;
}
if (auto Err = G->get()->generateDocForInfo(I, InfoOS))
llvm::errs() << toString(std::move(Err)) << "\n";
if (G->get()->generateDocForInfo(I, InfoOS))
llvm::errs() << "Unable to generate docs for info.\n";
}
return 0;

View File

@@ -14,7 +14,6 @@ add_clang_library(clangMove
clangFormat
clangFrontend
clangLex
clangSerialization
clangTooling
clangToolingCore
)

View File

@@ -76,7 +76,10 @@ std::string MakeAbsolutePath(StringRef CurrentDir, StringRef Path) {
return "";
llvm::SmallString<128> InitialDirectory(CurrentDir);
llvm::SmallString<128> AbsolutePath(Path);
llvm::sys::fs::make_absolute(InitialDirectory, AbsolutePath);
if (std::error_code EC =
llvm::sys::fs::make_absolute(InitialDirectory, AbsolutePath))
llvm::errs() << "Warning: could not make absolute file: '" << EC.message()
<< '\n';
return CleanPath(std::move(AbsolutePath));
}
@@ -114,7 +117,7 @@ AST_POLYMORPHIC_MATCHER_P(isExpansionInFile,
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc),
std::string, AbsoluteFilePath) {
auto &SourceManager = Finder->getASTContext().getSourceManager();
auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getBeginLoc());
auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart());
if (ExpansionLoc.isInvalid())
return false;
auto FileEntry =
@@ -125,17 +128,18 @@ AST_POLYMORPHIC_MATCHER_P(isExpansionInFile,
AbsoluteFilePath;
}
class FindAllIncludes : public PPCallbacks {
class FindAllIncludes : public clang::PPCallbacks {
public:
explicit FindAllIncludes(SourceManager *SM, ClangMoveTool *const MoveTool)
: SM(*SM), MoveTool(MoveTool) {}
void InclusionDirective(SourceLocation HashLoc, const Token & /*IncludeTok*/,
void InclusionDirective(clang::SourceLocation HashLoc,
const clang::Token & /*IncludeTok*/,
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
const FileEntry * /*File*/, StringRef SearchPath,
StringRef /*RelativePath*/,
const Module * /*Imported*/,
clang::CharSourceRange FilenameRange,
const clang::FileEntry * /*File*/,
StringRef SearchPath, StringRef /*RelativePath*/,
const clang::Module * /*Imported*/,
SrcMgr::CharacteristicKind /*FileType*/) override {
if (const auto *FileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc)))
MoveTool->addIncludes(FileName, IsAngled, SearchPath,
@@ -161,9 +165,9 @@ public:
: MoveTool(MoveTool) {}
void run(const MatchFinder::MatchResult &Result) override {
const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("function");
const auto *FD = Result.Nodes.getNodeAs<clang::FunctionDecl>("function");
assert(FD);
const NamedDecl *D = FD;
const clang::NamedDecl *D = FD;
if (const auto *FTD = FD->getDescribedFunctionTemplate())
D = FTD;
MoveDeclFromOldFileToNewFile(MoveTool, D);
@@ -179,7 +183,7 @@ public:
: MoveTool(MoveTool) {}
void run(const MatchFinder::MatchResult &Result) override {
const auto *VD = Result.Nodes.getNodeAs<VarDecl>("var");
const auto *VD = Result.Nodes.getNodeAs<clang::VarDecl>("var");
assert(VD);
MoveDeclFromOldFileToNewFile(MoveTool, VD);
}
@@ -194,10 +198,10 @@ public:
: MoveTool(MoveTool) {}
void run(const MatchFinder::MatchResult &Result) override {
if (const auto *TD = Result.Nodes.getNodeAs<TypedefDecl>("typedef"))
if (const auto *TD = Result.Nodes.getNodeAs<clang::TypedefDecl>("typedef"))
MoveDeclFromOldFileToNewFile(MoveTool, TD);
else if (const auto *TAD =
Result.Nodes.getNodeAs<TypeAliasDecl>("type_alias")) {
Result.Nodes.getNodeAs<clang::TypeAliasDecl>("type_alias")) {
const NamedDecl * D = TAD;
if (const auto * TD = TAD->getDescribedAliasTemplate())
D = TD;
@@ -215,7 +219,7 @@ public:
: MoveTool(MoveTool) {}
void run(const MatchFinder::MatchResult &Result) override {
const auto *ED = Result.Nodes.getNodeAs<EnumDecl>("enum");
const auto *ED = Result.Nodes.getNodeAs<clang::EnumDecl>("enum");
assert(ED);
MoveDeclFromOldFileToNewFile(MoveTool, ED);
}
@@ -229,19 +233,21 @@ public:
explicit ClassDeclarationMatch(ClangMoveTool *MoveTool)
: MoveTool(MoveTool) {}
void run(const MatchFinder::MatchResult &Result) override {
SourceManager *SM = &Result.Context->getSourceManager();
if (const auto *CMD = Result.Nodes.getNodeAs<CXXMethodDecl>("class_method"))
clang::SourceManager* SM = &Result.Context->getSourceManager();
if (const auto *CMD =
Result.Nodes.getNodeAs<clang::CXXMethodDecl>("class_method"))
MatchClassMethod(CMD, SM);
else if (const auto *VD =
Result.Nodes.getNodeAs<VarDecl>("class_static_var_decl"))
else if (const auto *VD = Result.Nodes.getNodeAs<clang::VarDecl>(
"class_static_var_decl"))
MatchClassStaticVariable(VD, SM);
else if (const auto *CD =
Result.Nodes.getNodeAs<CXXRecordDecl>("moved_class"))
else if (const auto *CD = Result.Nodes.getNodeAs<clang::CXXRecordDecl>(
"moved_class"))
MatchClassDeclaration(CD, SM);
}
private:
void MatchClassMethod(const CXXMethodDecl *CMD, SourceManager *SM) {
void MatchClassMethod(const clang::CXXMethodDecl* CMD,
clang::SourceManager* SM) {
// Skip inline class methods. isInline() ast matcher doesn't ignore this
// case.
if (!CMD->isInlined()) {
@@ -256,11 +262,13 @@ private:
}
}
void MatchClassStaticVariable(const NamedDecl *VD, SourceManager *SM) {
void MatchClassStaticVariable(const clang::NamedDecl *VD,
clang::SourceManager* SM) {
MoveDeclFromOldFileToNewFile(MoveTool, VD);
}
void MatchClassDeclaration(const CXXRecordDecl *CD, SourceManager *SM) {
void MatchClassDeclaration(const clang::CXXRecordDecl *CD,
clang::SourceManager* SM) {
// Get class template from its class declaration as UnremovedDecls stores
// class template.
if (const auto *TC = CD->getDescribedClassTemplate())
@@ -277,13 +285,14 @@ private:
// Expand to get the end location of the line where the EndLoc of the given
// Decl.
SourceLocation getLocForEndOfDecl(const Decl *D,
const LangOptions &LangOpts = LangOptions()) {
SourceLocation
getLocForEndOfDecl(const clang::Decl *D,
const LangOptions &LangOpts = clang::LangOptions()) {
const auto &SM = D->getASTContext().getSourceManager();
// If the expansion range is a character range, this is the location of
// the first character past the end. Otherwise it's the location of the
// first character in the final token in the range.
auto EndExpansionLoc = SM.getExpansionRange(D->getEndLoc()).getEnd();
auto EndExpansionLoc = SM.getExpansionRange(D->getLocEnd()).getEnd();
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(EndExpansionLoc);
// Try to load the file buffer.
bool InvalidTemp = false;
@@ -310,36 +319,39 @@ SourceLocation getLocForEndOfDecl(const Decl *D,
}
// Get full range of a Decl including the comments associated with it.
CharSourceRange getFullRange(const Decl *D,
const LangOptions &options = LangOptions()) {
clang::CharSourceRange
getFullRange(const clang::Decl *D,
const clang::LangOptions &options = clang::LangOptions()) {
const auto &SM = D->getASTContext().getSourceManager();
SourceRange Full(SM.getExpansionLoc(D->getBeginLoc()), getLocForEndOfDecl(D));
clang::SourceRange Full(SM.getExpansionLoc(D->getLocStart()),
getLocForEndOfDecl(D));
// Expand to comments that are associated with the Decl.
if (const auto *Comment = D->getASTContext().getRawCommentForDeclNoCache(D)) {
if (SM.isBeforeInTranslationUnit(Full.getEnd(), Comment->getEndLoc()))
Full.setEnd(Comment->getEndLoc());
if (SM.isBeforeInTranslationUnit(Full.getEnd(), Comment->getLocEnd()))
Full.setEnd(Comment->getLocEnd());
// FIXME: Don't delete a preceding comment, if there are no other entities
// it could refer to.
if (SM.isBeforeInTranslationUnit(Comment->getBeginLoc(), Full.getBegin()))
Full.setBegin(Comment->getBeginLoc());
if (SM.isBeforeInTranslationUnit(Comment->getLocStart(), Full.getBegin()))
Full.setBegin(Comment->getLocStart());
}
return CharSourceRange::getCharRange(Full);
return clang::CharSourceRange::getCharRange(Full);
}
std::string getDeclarationSourceText(const Decl *D) {
std::string getDeclarationSourceText(const clang::Decl *D) {
const auto &SM = D->getASTContext().getSourceManager();
llvm::StringRef SourceText =
Lexer::getSourceText(getFullRange(D), SM, LangOptions());
clang::Lexer::getSourceText(getFullRange(D), SM, clang::LangOptions());
return SourceText.str();
}
bool isInHeaderFile(const Decl *D, llvm::StringRef OriginalRunningDirectory,
bool isInHeaderFile(const clang::Decl *D,
llvm::StringRef OriginalRunningDirectory,
llvm::StringRef OldHeader) {
const auto &SM = D->getASTContext().getSourceManager();
if (OldHeader.empty())
return false;
auto ExpansionLoc = SM.getExpansionLoc(D->getBeginLoc());
auto ExpansionLoc = SM.getExpansionLoc(D->getLocStart());
if (ExpansionLoc.isInvalid())
return false;
@@ -351,22 +363,22 @@ bool isInHeaderFile(const Decl *D, llvm::StringRef OriginalRunningDirectory,
return false;
}
std::vector<std::string> getNamespaces(const Decl *D) {
std::vector<std::string> getNamespaces(const clang::Decl *D) {
std::vector<std::string> Namespaces;
for (const auto *Context = D->getDeclContext(); Context;
Context = Context->getParent()) {
if (llvm::isa<TranslationUnitDecl>(Context) ||
llvm::isa<LinkageSpecDecl>(Context))
if (llvm::isa<clang::TranslationUnitDecl>(Context) ||
llvm::isa<clang::LinkageSpecDecl>(Context))
break;
if (const auto *ND = llvm::dyn_cast<NamespaceDecl>(Context))
if (const auto *ND = llvm::dyn_cast<clang::NamespaceDecl>(Context))
Namespaces.push_back(ND->getName().str());
}
std::reverse(Namespaces.begin(), Namespaces.end());
return Namespaces;
}
tooling::Replacements
clang::tooling::Replacements
createInsertedReplacements(const std::vector<std::string> &Includes,
const std::vector<const NamedDecl *> &Decls,
llvm::StringRef FileName, bool IsHeader = false,
@@ -451,7 +463,8 @@ createInsertedReplacements(const std::vector<std::string> &Includes,
if (IsHeader)
NewCode += "\n#endif // " + GuardName + "\n";
return tooling::Replacements(tooling::Replacement(FileName, 0, 0, NewCode));
return clang::tooling::Replacements(
clang::tooling::Replacement(FileName, 0, 0, NewCode));
}
// Return a set of all decls which are used/referenced by the given Decls.
@@ -475,8 +488,8 @@ getUsedDecls(const HelperDeclRefGraph *RG,
} // namespace
std::unique_ptr<ASTConsumer>
ClangMoveAction::CreateASTConsumer(CompilerInstance &Compiler,
std::unique_ptr<clang::ASTConsumer>
ClangMoveAction::CreateASTConsumer(clang::CompilerInstance &Compiler,
StringRef /*InFile*/) {
Compiler.getPreprocessor().addPPCallbacks(llvm::make_unique<FindAllIncludes>(
&Compiler.getSourceManager(), &MoveTool));
@@ -545,8 +558,7 @@ void ClangMoveTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
// namespace, these decls are always copied to new.h/cc. Those in classes,
// functions are covered in other matchers.
Finder->addMatcher(namedDecl(anyOf(usingDecl(IsOldCCTopLevelDecl),
usingDirectiveDecl(unless(isImplicit()),
IsOldCCTopLevelDecl),
usingDirectiveDecl(IsOldCCTopLevelDecl),
typeAliasDecl(IsOldCCTopLevelDecl)),
notInMacro())
.bind("using_decl"),
@@ -660,10 +672,11 @@ void ClangMoveTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
}
void ClangMoveTool::run(const ast_matchers::MatchFinder::MatchResult &Result) {
if (const auto *D = Result.Nodes.getNodeAs<NamedDecl>("decls_in_header")) {
if (const auto *D =
Result.Nodes.getNodeAs<clang::NamedDecl>("decls_in_header")) {
UnremovedDeclsInOldHeader.insert(D);
} else if (const auto *FWD =
Result.Nodes.getNodeAs<CXXRecordDecl>("fwd_decl")) {
Result.Nodes.getNodeAs<clang::CXXRecordDecl>("fwd_decl")) {
// Skip all forward declarations which appear after moved class declaration.
if (RemovedDecls.empty()) {
if (const auto *DCT = FWD->getDescribedClassTemplate())
@@ -672,12 +685,13 @@ void ClangMoveTool::run(const ast_matchers::MatchFinder::MatchResult &Result) {
MovedDecls.push_back(FWD);
}
} else if (const auto *ND =
Result.Nodes.getNodeAs<NamedDecl>("helper_decls")) {
Result.Nodes.getNodeAs<clang::NamedDecl>("helper_decls")) {
MovedDecls.push_back(ND);
HelperDeclarations.push_back(ND);
LLVM_DEBUG(llvm::dbgs() << "Add helper : " << ND->getNameAsString() << " ("
<< ND << ")\n");
} else if (const auto *UD = Result.Nodes.getNodeAs<NamedDecl>("using_decl")) {
} else if (const auto *UD =
Result.Nodes.getNodeAs<clang::NamedDecl>("using_decl")) {
MovedDecls.push_back(UD);
}
}
@@ -689,7 +703,7 @@ std::string ClangMoveTool::makeAbsolutePath(StringRef Path) {
void ClangMoveTool::addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
llvm::StringRef SearchPath,
llvm::StringRef FileName,
CharSourceRange IncludeFilenameRange,
clang::CharSourceRange IncludeFilenameRange,
const SourceManager &SM) {
SmallVector<char, 128> HeaderWithSearchPath;
llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
@@ -749,8 +763,9 @@ void ClangMoveTool::removeDeclsInOldFiles() {
for (const auto *RemovedDecl : RemovedDecls) {
const auto &SM = RemovedDecl->getASTContext().getSourceManager();
auto Range = getFullRange(RemovedDecl);
tooling::Replacement RemoveReplacement(
SM, CharSourceRange::getCharRange(Range.getBegin(), Range.getEnd()),
clang::tooling::Replacement RemoveReplacement(
SM,
clang::CharSourceRange::getCharRange(Range.getBegin(), Range.getEnd()),
"");
std::string FilePath = RemoveReplacement.getFilePath().str();
auto Err = Context->FileToReplacements[FilePath].add(RemoveReplacement);
@@ -780,8 +795,7 @@ void ClangMoveTool::removeDeclsInOldFiles() {
// Ignore replacements for new.h/cc.
if (SI == FilePathToFileID.end()) continue;
llvm::StringRef Code = SM.getBufferData(SI->second);
auto Style = format::getStyle(format::DefaultFormatStyle, FilePath,
Context->FallbackStyle);
auto Style = format::getStyle("file", FilePath, Context->FallbackStyle);
if (!Style) {
llvm::errs() << llvm::toString(Style.takeError()) << "\n";
continue;
@@ -852,18 +866,20 @@ void ClangMoveTool::moveAll(SourceManager &SM, StringRef OldFile,
FileID ID = SM.getOrCreateFileID(FE, SrcMgr::C_User);
auto Begin = SM.getLocForStartOfFile(ID);
auto End = SM.getLocForEndOfFile(ID);
tooling::Replacement RemoveAll(SM, CharSourceRange::getCharRange(Begin, End),
"");
clang::tooling::Replacement RemoveAll (
SM, clang::CharSourceRange::getCharRange(Begin, End), "");
std::string FilePath = RemoveAll.getFilePath().str();
Context->FileToReplacements[FilePath] = tooling::Replacements(RemoveAll);
Context->FileToReplacements[FilePath] =
clang::tooling::Replacements(RemoveAll);
StringRef Code = SM.getBufferData(ID);
if (!NewFile.empty()) {
auto AllCode =
tooling::Replacements(tooling::Replacement(NewFile, 0, 0, Code));
auto ReplaceOldInclude = [&](CharSourceRange OldHeaderIncludeRange) {
AllCode = AllCode.merge(tooling::Replacements(tooling::Replacement(
SM, OldHeaderIncludeRange, '"' + Context->Spec.NewHeader + '"')));
auto AllCode = clang::tooling::Replacements(
clang::tooling::Replacement(NewFile, 0, 0, Code));
auto ReplaceOldInclude = [&](clang::CharSourceRange OldHeaderIncludeRange) {
AllCode = AllCode.merge(clang::tooling::Replacements(
clang::tooling::Replacement(SM, OldHeaderIncludeRange,
'"' + Context->Spec.NewHeader + '"')));
};
// Fix the case where old.h/old.cc includes "old.h", we replace the
// `#include "old.h"` with `#include "new.h"`.
@@ -881,21 +897,21 @@ void ClangMoveTool::onEndOfTranslationUnit() {
assert(Reporter);
for (const auto *Decl : UnremovedDeclsInOldHeader) {
auto Kind = Decl->getKind();
bool Templated = Decl->isTemplated();
const std::string QualifiedName = Decl->getQualifiedNameAsString();
if (Kind == Decl::Kind::Var)
Reporter->reportDeclaration(QualifiedName, "Variable", Templated);
Reporter->reportDeclaration(QualifiedName, "Variable");
else if (Kind == Decl::Kind::Function ||
Kind == Decl::Kind::FunctionTemplate)
Reporter->reportDeclaration(QualifiedName, "Function", Templated);
Reporter->reportDeclaration(QualifiedName, "Function");
else if (Kind == Decl::Kind::ClassTemplate ||
Kind == Decl::Kind::CXXRecord)
Reporter->reportDeclaration(QualifiedName, "Class", Templated);
Reporter->reportDeclaration(QualifiedName, "Class");
else if (Kind == Decl::Kind::Enum)
Reporter->reportDeclaration(QualifiedName, "Enum", Templated);
else if (Kind == Decl::Kind::Typedef || Kind == Decl::Kind::TypeAlias ||
Reporter->reportDeclaration(QualifiedName, "Enum");
else if (Kind == Decl::Kind::Typedef ||
Kind == Decl::Kind::TypeAlias ||
Kind == Decl::Kind::TypeAliasTemplate)
Reporter->reportDeclaration(QualifiedName, "TypeAlias", Templated);
Reporter->reportDeclaration(QualifiedName, "TypeAlias");
}
return;
}
@@ -905,7 +921,7 @@ void ClangMoveTool::onEndOfTranslationUnit() {
// Ignore symbols that are not supported when checking if there is unremoved
// symbol in old header. This makes sure that we always move old files to new
// files when all symbols produced from dump_decls are moved.
auto IsSupportedKind = [](const NamedDecl *Decl) {
auto IsSupportedKind = [](const clang::NamedDecl *Decl) {
switch (Decl->getKind()) {
case Decl::Kind::Function:
case Decl::Kind::FunctionTemplate:

View File

@@ -17,7 +17,6 @@
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include <map>
#include <memory>
#include <string>
@@ -32,30 +31,23 @@ public:
DeclarationReporter() = default;
~DeclarationReporter() = default;
void reportDeclaration(llvm::StringRef DeclarationName, llvm::StringRef Type,
bool Templated) {
DeclarationList.emplace_back(DeclarationName, Type, Templated);
void reportDeclaration(llvm::StringRef DeclarationName,
llvm::StringRef Type) {
DeclarationList.emplace_back(DeclarationName, Type);
};
struct Declaration {
Declaration(llvm::StringRef QName, llvm::StringRef Kind, bool Templated)
: QualifiedName(QName), Kind(Kind), Templated(Templated) {}
// A <DeclarationName, DeclarationKind> pair.
// The DeclarationName is a fully qualified name for the declaration, like
// A::B::Foo. The DeclarationKind is a string represents the kind of the
// declaration, currently only "Function" and "Class" are supported.
typedef std::pair<std::string, std::string> DeclarationPair;
friend bool operator==(const Declaration &LHS, const Declaration &RHS) {
return std::tie(LHS.QualifiedName, LHS.Kind, LHS.Templated) ==
std::tie(RHS.QualifiedName, RHS.Kind, RHS.Templated);
}
std::string QualifiedName; // E.g. A::B::Foo.
std::string Kind; // E.g. Function, Class
bool Templated = false; // Whether the declaration is templated.
};
const std::vector<Declaration> getDeclarationList() const {
const std::vector<DeclarationPair> getDeclarationList() const {
return DeclarationList;
}
private:
std::vector<Declaration> DeclarationList;
std::vector<DeclarationPair> DeclarationList;
};
// Specify declarations being moved. It contains all information of the moved

View File

@@ -13,7 +13,6 @@ target_link_libraries(clang-move
clangFrontend
clangMove
clangRewrite
clangSerialization
clangTooling
clangToolingCore
)

View File

@@ -128,7 +128,7 @@ int main(int argc, const char **argv) {
InitialDirectory.str(), Style, DumpDecls};
move::DeclarationReporter Reporter;
move::ClangMoveActionFactory Factory(&Context, &Reporter);
int CodeStatus = Tool.run(&Factory);
if (CodeStatus)
return CodeStatus;
@@ -138,11 +138,8 @@ int main(int argc, const char **argv) {
const auto &Declarations = Reporter.getDeclarationList();
for (auto I = Declarations.begin(), E = Declarations.end(); I != E; ++I) {
llvm::outs() << " {\n";
llvm::outs() << " \"DeclarationName\": \"" << I->QualifiedName
<< "\",\n";
llvm::outs() << " \"DeclarationType\": \"" << I->Kind << "\",\n";
llvm::outs() << " \"Templated\": " << (I->Templated ? "true" : "false")
<< "\n";
llvm::outs() << " \"DeclarationName\": \"" << I->first << "\",\n";
llvm::outs() << " \"DeclarationType\": \"" << I->second << "\"\n";
llvm::outs() << " }";
// Don't print trailing "," at the end of last element.
if (I != std::prev(E))

View File

@@ -13,7 +13,6 @@ add_clang_library(clangQuery
clangBasic
clangDynamicASTMatchers
clangFrontend
clangSerialization
)
add_subdirectory(tool)

View File

@@ -41,26 +41,12 @@ bool HelpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
"as part of other expressions.\n"
" set bind-root (true|false) "
"Set whether to bind the root matcher to \"root\".\n"
" set print-matcher (true|false) "
"Set whether to print the current matcher,\n"
" set output <feature> "
"Set whether to output only <feature> content.\n"
" enable output <feature> "
"Enable <feature> content non-exclusively.\n"
" disable output <feature> "
"Disable <feature> content non-exclusively.\n"
" quit, q "
"Terminates the query session.\n\n"
"Several commands accept a <feature> parameter. The available features "
"are:\n\n"
" print "
"Pretty-print bound nodes.\n"
" diag "
"Diagnostic location for bound nodes.\n"
" detailed-ast "
"Detailed AST output for bound nodes.\n"
" dump "
"Detailed AST output for bound nodes (alias of detailed-ast).\n\n";
" set output (diag|print|dump) "
"Set whether to print bindings as diagnostics,\n"
" "
"AST pretty prints or AST dumps.\n"
" quit "
"Terminates the query session.\n\n";
return true;
}
@@ -100,18 +86,13 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
}
Finder.matchAST(AST->getASTContext());
if (QS.PrintMatcher) {
std::string prefixText = "Matcher: ";
OS << "\n " << prefixText << Source << "\n";
OS << " " << std::string(prefixText.size() + Source.size(), '=') << '\n';
}
for (auto MI = Matches.begin(), ME = Matches.end(); MI != ME; ++MI) {
OS << "\nMatch #" << ++MatchCount << ":\n\n";
for (auto BI = MI->getMap().begin(), BE = MI->getMap().end(); BI != BE;
++BI) {
if (QS.DiagOutput) {
switch (QS.OutKind) {
case OK_Diag: {
clang::SourceRange R = BI->second.getSourceRange();
if (R.isValid()) {
TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
@@ -121,16 +102,20 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here",
CharSourceRange::getTokenRange(R), None);
}
break;
}
if (QS.PrintOutput) {
case OK_Print: {
OS << "Binding for \"" << BI->first << "\":\n";
BI->second.print(OS, AST->getASTContext().getPrintingPolicy());
OS << "\n";
break;
}
if (QS.DetailedASTOutput) {
case OK_Dump: {
OS << "Binding for \"" << BI->first << "\":\n";
BI->second.dump(OS, AST->getSourceManager());
OS << "\n";
break;
}
}
}

View File

@@ -10,7 +10,6 @@
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_H
#include "QuerySession.h"
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
@@ -19,7 +18,7 @@
namespace clang {
namespace query {
enum OutputKind { OK_Diag, OK_Print, OK_DetailedAST };
enum OutputKind { OK_Diag, OK_Print, OK_Dump };
enum QueryKind {
QK_Invalid,
@@ -29,8 +28,6 @@ enum QueryKind {
QK_Match,
QK_SetBool,
QK_SetOutputKind,
QK_EnableOutputKind,
QK_DisableOutputKind,
QK_Quit
};
@@ -86,15 +83,12 @@ struct QuitQuery : Query {
/// Query for "match MATCHER".
struct MatchQuery : Query {
MatchQuery(StringRef Source,
const ast_matchers::dynamic::DynTypedMatcher &Matcher)
: Query(QK_Match), Matcher(Matcher), Source(Source) {}
MatchQuery(const ast_matchers::dynamic::DynTypedMatcher &Matcher)
: Query(QK_Match), Matcher(Matcher) {}
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override;
ast_matchers::dynamic::DynTypedMatcher Matcher;
StringRef Source;
static bool classof(const Query *Q) { return Q->Kind == QK_Match; }
};
@@ -136,53 +130,6 @@ template <typename T> struct SetQuery : Query {
T Value;
};
// Implements the exclusive 'set output dump|diag|print' options.
struct SetExclusiveOutputQuery : Query {
SetExclusiveOutputQuery(bool QuerySession::*Var)
: Query(QK_SetOutputKind), Var(Var) {}
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override {
QS.DiagOutput = false;
QS.DetailedASTOutput = false;
QS.PrintOutput = false;
QS.*Var = true;
return true;
}
static bool classof(const Query *Q) { return Q->Kind == QK_SetOutputKind; }
bool QuerySession::*Var;
};
// Implements the non-exclusive 'set output dump|diag|print' options.
struct SetNonExclusiveOutputQuery : Query {
SetNonExclusiveOutputQuery(QueryKind Kind, bool QuerySession::*Var,
bool Value)
: Query(Kind), Var(Var), Value(Value) {}
bool run(llvm::raw_ostream &OS, QuerySession &QS) const override {
QS.*Var = Value;
return true;
}
bool QuerySession::*Var;
bool Value;
};
struct EnableOutputQuery : SetNonExclusiveOutputQuery {
EnableOutputQuery(bool QuerySession::*Var)
: SetNonExclusiveOutputQuery(QK_EnableOutputKind, Var, true) {}
static bool classof(const Query *Q) { return Q->Kind == QK_EnableOutputKind; }
};
struct DisableOutputQuery : SetNonExclusiveOutputQuery {
DisableOutputQuery(bool QuerySession::*Var)
: SetNonExclusiveOutputQuery(QK_DisableOutputKind, Var, false) {}
static bool classof(const Query *Q) {
return Q->Kind == QK_DisableOutputKind;
}
};
} // namespace query
} // namespace clang

View File

@@ -27,22 +27,24 @@ namespace query {
// is found before End, return StringRef(). Begin is adjusted to exclude the
// lexed region.
StringRef QueryParser::lexWord() {
Line = Line.ltrim();
while (true) {
if (Begin == End)
return StringRef(Begin, 0);
if (Line.empty())
// Even though the Line is empty, it contains a pointer and
// a (zero) length. The pointer is used in the LexOrCompleteWord
// code completion.
return Line;
if (!isWhitespace(*Begin))
break;
if (Line.front() == '#') {
Line = {};
return StringRef();
++Begin;
}
StringRef Word = Line.take_until(isWhitespace);
Line = Line.drop_front(Word.size());
return Word;
const char *WordBegin = Begin;
while (true) {
++Begin;
if (Begin == End || isWhitespace(*Begin))
return StringRef(WordBegin, Begin - WordBegin);
}
}
// This is the StringSwitch-alike used by lexOrCompleteWord below. See that
@@ -99,36 +101,25 @@ QueryRef QueryParser::parseSetBool(bool QuerySession::*Var) {
return new SetQuery<bool>(Var, Value);
}
template <typename QueryType> QueryRef QueryParser::parseSetOutputKind() {
QueryRef QueryParser::parseSetOutputKind() {
StringRef ValStr;
unsigned OutKind = LexOrCompleteWord<unsigned>(this, ValStr)
.Case("diag", OK_Diag)
.Case("print", OK_Print)
.Case("detailed-ast", OK_DetailedAST)
.Case("dump", OK_DetailedAST)
.Case("dump", OK_Dump)
.Default(~0u);
if (OutKind == ~0u) {
return new InvalidQuery(
"expected 'diag', 'print', 'detailed-ast' or 'dump', got '" + ValStr +
"'");
return new InvalidQuery("expected 'diag', 'print' or 'dump', got '" +
ValStr + "'");
}
switch (OutKind) {
case OK_DetailedAST:
return new QueryType(&QuerySession::DetailedASTOutput);
case OK_Diag:
return new QueryType(&QuerySession::DiagOutput);
case OK_Print:
return new QueryType(&QuerySession::PrintOutput);
}
llvm_unreachable("Invalid output kind");
return new SetQuery<OutputKind>(&QuerySession::OutKind, OutputKind(OutKind));
}
QueryRef QueryParser::endQuery(QueryRef Q) {
const StringRef Extra = Line;
const char *Extra = Begin;
if (!lexWord().empty())
return new InvalidQuery("unexpected extra input: '" + Extra + "'");
return new InvalidQuery("unexpected extra input: '" +
StringRef(Extra, End - Extra) + "'");
return Q;
}
@@ -136,24 +127,16 @@ namespace {
enum ParsedQueryKind {
PQK_Invalid,
PQK_Comment,
PQK_NoOp,
PQK_Help,
PQK_Let,
PQK_Match,
PQK_Set,
PQK_Unlet,
PQK_Quit,
PQK_Enable,
PQK_Disable
PQK_Quit
};
enum ParsedQueryVariable {
PQV_Invalid,
PQV_Output,
PQV_BindRoot,
PQV_PrintMatcher
};
enum ParsedQueryVariable { PQV_Invalid, PQV_Output, PQV_BindRoot };
QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) {
std::string ErrStr;
@@ -166,7 +149,8 @@ QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) {
QueryRef QueryParser::completeMatcherExpression() {
std::vector<MatcherCompletion> Comps = Parser::completeExpression(
Line, CompletionPos - Line.begin(), nullptr, &QS.NamedValues);
StringRef(Begin, End - Begin), CompletionPos - Begin, nullptr,
&QS.NamedValues);
for (auto I = Comps.begin(), E = Comps.end(); I != E; ++I) {
Completions.push_back(LineEditor::Completion(I->TypedText, I->MatcherDecl));
}
@@ -177,22 +161,16 @@ QueryRef QueryParser::doParse() {
StringRef CommandStr;
ParsedQueryKind QKind = LexOrCompleteWord<ParsedQueryKind>(this, CommandStr)
.Case("", PQK_NoOp)
.Case("#", PQK_Comment, /*IsCompletion=*/false)
.Case("help", PQK_Help)
.Case("l", PQK_Let, /*IsCompletion=*/false)
.Case("let", PQK_Let)
.Case("m", PQK_Match, /*IsCompletion=*/false)
.Case("let", PQK_Let)
.Case("match", PQK_Match)
.Case("q", PQK_Quit, /*IsCompletion=*/false)
.Case("quit", PQK_Quit)
.Case("set", PQK_Set)
.Case("enable", PQK_Enable)
.Case("disable", PQK_Disable)
.Case("unlet", PQK_Unlet)
.Case("quit", PQK_Quit)
.Default(PQK_Invalid);
switch (QKind) {
case PQK_Comment:
case PQK_NoOp:
return new NoOpQuery;
@@ -213,8 +191,8 @@ QueryRef QueryParser::doParse() {
Diagnostics Diag;
ast_matchers::dynamic::VariantValue Value;
if (!Parser::parseExpression(Line, nullptr, &QS.NamedValues, &Value,
&Diag)) {
if (!Parser::parseExpression(StringRef(Begin, End - Begin), nullptr,
&QS.NamedValues, &Value, &Diag)) {
return makeInvalidQueryFromDiagnostics(Diag);
}
@@ -226,23 +204,21 @@ QueryRef QueryParser::doParse() {
return completeMatcherExpression();
Diagnostics Diag;
auto MatcherSource = Line.trim();
Optional<DynTypedMatcher> Matcher = Parser::parseMatcherExpression(
MatcherSource, nullptr, &QS.NamedValues, &Diag);
StringRef(Begin, End - Begin), nullptr, &QS.NamedValues, &Diag);
if (!Matcher) {
return makeInvalidQueryFromDiagnostics(Diag);
}
return new MatchQuery(MatcherSource, *Matcher);
return new MatchQuery(*Matcher);
}
case PQK_Set: {
StringRef VarStr;
ParsedQueryVariable Var =
LexOrCompleteWord<ParsedQueryVariable>(this, VarStr)
.Case("output", PQV_Output)
.Case("bind-root", PQV_BindRoot)
.Case("print-matcher", PQV_PrintMatcher)
.Default(PQV_Invalid);
ParsedQueryVariable Var = LexOrCompleteWord<ParsedQueryVariable>(this,
VarStr)
.Case("output", PQV_Output)
.Case("bind-root", PQV_BindRoot)
.Default(PQV_Invalid);
if (VarStr.empty())
return new InvalidQuery("expected variable name");
if (Var == PQV_Invalid)
@@ -251,42 +227,17 @@ QueryRef QueryParser::doParse() {
QueryRef Q;
switch (Var) {
case PQV_Output:
Q = parseSetOutputKind<SetExclusiveOutputQuery>();
Q = parseSetOutputKind();
break;
case PQV_BindRoot:
Q = parseSetBool(&QuerySession::BindRoot);
break;
case PQV_PrintMatcher:
Q = parseSetBool(&QuerySession::PrintMatcher);
break;
case PQV_Invalid:
llvm_unreachable("Invalid query kind");
}
return endQuery(Q);
}
case PQK_Enable:
case PQK_Disable: {
StringRef VarStr;
ParsedQueryVariable Var =
LexOrCompleteWord<ParsedQueryVariable>(this, VarStr)
.Case("output", PQV_Output)
.Default(PQV_Invalid);
if (VarStr.empty())
return new InvalidQuery("expected variable name");
if (Var == PQV_Invalid)
return new InvalidQuery("unknown variable: '" + VarStr + "'");
QueryRef Q;
if (QKind == PQK_Enable)
Q = parseSetOutputKind<EnableOutputQuery>();
else if (QKind == PQK_Disable)
Q = parseSetOutputKind<DisableOutputQuery>();
else
llvm_unreachable("Invalid query kind");
return endQuery(Q);
}
case PQK_Unlet: {
StringRef Name = lexWord();

View File

@@ -37,14 +37,14 @@ public:
private:
QueryParser(StringRef Line, const QuerySession &QS)
: Line(Line), CompletionPos(nullptr), QS(QS) {}
: Begin(Line.begin()), End(Line.end()), CompletionPos(nullptr), QS(QS) {}
StringRef lexWord();
template <typename T> struct LexOrCompleteWord;
QueryRef parseSetBool(bool QuerySession::*Var);
template <typename QueryType> QueryRef parseSetOutputKind();
QueryRef parseSetOutputKind();
QueryRef completeMatcherExpression();
QueryRef endQuery(QueryRef Q);
@@ -55,7 +55,8 @@ private:
/// \c InvalidQuery if a parse error occurs.
QueryRef doParse();
StringRef Line;
const char *Begin;
const char *End;
const char *CompletionPos;
std::vector<llvm::LineEditor::Completion> Completions;

View File

@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_SESSION_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_SESSION_H
#include "Query.h"
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringMap.h"
@@ -24,18 +25,11 @@ namespace query {
class QuerySession {
public:
QuerySession(llvm::ArrayRef<std::unique_ptr<ASTUnit>> ASTs)
: ASTs(ASTs), PrintOutput(false), DiagOutput(true),
DetailedASTOutput(false), BindRoot(true), PrintMatcher(false),
Terminate(false) {}
: ASTs(ASTs), OutKind(OK_Diag), BindRoot(true), Terminate(false) {}
llvm::ArrayRef<std::unique_ptr<ASTUnit>> ASTs;
bool PrintOutput;
bool DiagOutput;
bool DetailedASTOutput;
OutputKind OutKind;
bool BindRoot;
bool PrintMatcher;
bool Terminate;
llvm::StringMap<ast_matchers::dynamic::VariantValue> NamedValues;
};

View File

@@ -9,7 +9,6 @@ target_link_libraries(clang-query
clangDynamicASTMatchers
clangFrontend
clangQuery
clangSerialization
clangTooling
)

View File

@@ -58,29 +58,6 @@ static cl::list<std::string> CommandFiles("f",
cl::value_desc("file"),
cl::cat(ClangQueryCategory));
static cl::opt<std::string> PreloadFile(
"preload",
cl::desc("Preload commands from file and start interactive mode"),
cl::value_desc("file"), cl::cat(ClangQueryCategory));
bool runCommandsInFile(const char *ExeName, std::string const &FileName,
QuerySession &QS) {
std::ifstream Input(FileName.c_str());
if (!Input.is_open()) {
llvm::errs() << ExeName << ": cannot open " << FileName << "\n";
return 1;
}
while (Input.good()) {
std::string Line;
std::getline(Input, Line);
QueryRef Q = QueryParser::parse(Line, QS);
if (!Q->run(llvm::outs(), QS))
return true;
}
return false;
}
int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
@@ -91,28 +68,11 @@ int main(int argc, const char **argv) {
return 1;
}
if ((!Commands.empty() || !CommandFiles.empty()) && !PreloadFile.empty()) {
llvm::errs() << argv[0]
<< ": cannot specify both -c or -f with --preload\n";
return 1;
}
ClangTool Tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
std::vector<std::unique_ptr<ASTUnit>> ASTs;
int Status = Tool.buildASTs(ASTs);
int ASTStatus = 0;
if (Status == 1) {
// Building ASTs failed.
if (Tool.buildASTs(ASTs) != 0)
return 1;
} else if (Status == 2) {
ASTStatus |= 1;
llvm::errs() << "Failed to build AST for some of the files, "
<< "results may be incomplete."
<< "\n";
} else {
assert(Status == 0 && "Unexpected status returned");
}
QuerySession QS(ASTs);
@@ -124,14 +84,21 @@ int main(int argc, const char **argv) {
}
} else if (!CommandFiles.empty()) {
for (auto I = CommandFiles.begin(), E = CommandFiles.end(); I != E; ++I) {
if (runCommandsInFile(argv[0], *I, QS))
std::ifstream Input(I->c_str());
if (!Input.is_open()) {
llvm::errs() << argv[0] << ": cannot open " << *I << "\n";
return 1;
}
while (Input.good()) {
std::string Line;
std::getline(Input, Line);
QueryRef Q = QueryParser::parse(Line, QS);
if (!Q->run(llvm::outs(), QS))
return 1;
}
}
} else {
if (!PreloadFile.empty()) {
if (runCommandsInFile(argv[0], PreloadFile, QS))
return 1;
}
LineEditor LE("clang-query");
LE.setListCompleter([&QS](StringRef Line, size_t Pos) {
return QueryParser::complete(Line, Pos, QS);
@@ -145,5 +112,5 @@ int main(int argc, const char **argv) {
}
}
return ASTStatus;
return 0;
}

View File

@@ -9,7 +9,6 @@ add_clang_library(clangReorderFields
clangBasic
clangIndex
clangLex
clangSerialization
clangToolingCore
)

View File

@@ -6,7 +6,6 @@ target_link_libraries(clang-reorder-fields
clangFrontend
clangReorderFields
clangRewrite
clangSerialization
clangTooling
clangToolingCore
)

View File

@@ -21,18 +21,12 @@ add_clang_library(clangTidy
clangLex
clangRewrite
clangSema
clangSerialization
clangStaticAnalyzerCore
clangStaticAnalyzerFrontend
clangTooling
clangToolingCore
)
if(CLANG_ENABLE_STATIC_ANALYZER)
target_link_libraries(clangTidy PRIVATE
clangStaticAnalyzerCore
clangStaticAnalyzerFrontend
)
endif()
add_subdirectory(android)
add_subdirectory(abseil)
add_subdirectory(boost)
@@ -45,9 +39,7 @@ add_subdirectory(hicpp)
add_subdirectory(llvm)
add_subdirectory(misc)
add_subdirectory(modernize)
if(CLANG_ENABLE_STATIC_ANALYZER)
add_subdirectory(mpi)
endif()
add_subdirectory(mpi)
add_subdirectory(objc)
add_subdirectory(performance)
add_subdirectory(plugin)

View File

@@ -23,7 +23,6 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Config/config.h"
#include "clang/Format/Format.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -35,10 +34,8 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
#if CLANG_ENABLE_STATIC_ANALYZER
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
#endif // CLANG_ENABLE_STATIC_ANALYZER
#include "clang/Tooling/DiagnosticsYaml.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/ReplacementsYaml.h"
@@ -59,7 +56,6 @@ namespace clang {
namespace tidy {
namespace {
#if CLANG_ENABLE_STATIC_ANALYZER
static const char *AnalyzerCheckNamePrefix = "clang-analyzer-";
class AnalyzerDiagnosticConsumer : public ento::PathDiagnosticConsumer {
@@ -91,12 +87,11 @@ public:
private:
ClangTidyContext &Context;
};
#endif // CLANG_ENABLE_STATIC_ANALYZER
class ErrorReporter {
public:
ErrorReporter(ClangTidyContext &Context, bool ApplyFixes,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS)
llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS)
: Files(FileSystemOptions(), BaseFS), DiagOpts(new DiagnosticOptions()),
DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)),
Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
@@ -127,6 +122,10 @@ public:
<< Message.Message << Name;
for (const auto &FileAndReplacements : Error.Fix) {
for (const auto &Repl : FileAndReplacements.second) {
// Retrieve the source range for applicable fixes. Macro definitions
// on the command line have locations in a virtual buffer and don't
// have valid file paths and are therefore not applicable.
SourceRange Range;
SourceLocation FixLoc;
++TotalFixes;
bool CanBeApplied = false;
@@ -167,11 +166,7 @@ public:
FixLoc = getLocation(FixAbsoluteFilePath, Repl.getOffset());
SourceLocation FixEndLoc =
FixLoc.getLocWithOffset(Repl.getLength());
// Retrieve the source range for applicable fixes. Macro definitions
// on the command line have locations in a virtual buffer and don't
// have valid file paths and are therefore not applicable.
CharSourceRange Range =
CharSourceRange::getCharRange(SourceRange(FixLoc, FixEndLoc));
Range = SourceRange(FixLoc, FixEndLoc);
Diag << FixItHint::CreateReplacement(Range,
Repl.getReplacementText());
}
@@ -301,7 +296,6 @@ ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
}
}
#if CLANG_ENABLE_STATIC_ANALYZER
static void setStaticAnalyzerCheckerOpts(const ClangTidyOptions &Opts,
AnalyzerOptionsRef AnalyzerOptions) {
StringRef AnalyzerPrefix(AnalyzerCheckNamePrefix);
@@ -345,7 +339,6 @@ static CheckersList getCheckersControlList(ClangTidyContext &Context,
}
return List;
}
#endif // CLANG_ENABLE_STATIC_ANALYZER
std::unique_ptr<clang::ASTConsumer>
ClangTidyASTConsumerFactory::CreateASTConsumer(
@@ -387,7 +380,6 @@ ClangTidyASTConsumerFactory::CreateASTConsumer(
if (!Checks.empty())
Consumers.push_back(Finder->newASTConsumer());
#if CLANG_ENABLE_STATIC_ANALYZER
AnalyzerOptionsRef AnalyzerOptions = Compiler.getAnalyzerOpts();
AnalyzerOptions->CheckersControlList =
getCheckersControlList(Context, Context.canEnableAnalyzerAlphaCheckers());
@@ -403,7 +395,6 @@ ClangTidyASTConsumerFactory::CreateASTConsumer(
new AnalyzerDiagnosticConsumer(Context));
Consumers.push_back(std::move(AnalysisConsumer));
}
#endif // CLANG_ENABLE_STATIC_ANALYZER
return llvm::make_unique<ClangTidyASTConsumer>(
std::move(Consumers), std::move(Profiling), std::move(Finder),
std::move(Checks));
@@ -416,11 +407,9 @@ std::vector<std::string> ClangTidyASTConsumerFactory::getCheckNames() {
CheckNames.push_back(CheckFactory.first);
}
#if CLANG_ENABLE_STATIC_ANALYZER
for (const auto &AnalyzerCheck : getCheckersControlList(
Context, Context.canEnableAnalyzerAlphaCheckers()))
CheckNames.push_back(AnalyzerCheckNamePrefix + AnalyzerCheck.first);
#endif // CLANG_ENABLE_STATIC_ANALYZER
std::sort(CheckNames.begin(), CheckNames.end());
return CheckNames;
@@ -441,9 +430,7 @@ DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc, StringRef Message,
}
void ClangTidyCheck::run(const ast_matchers::MatchFinder::MatchResult &Result) {
// For historical reasons, checks don't implement the MatchFinder run()
// callback directly. We keep the run()/check() distinction to avoid interface
// churn, and to allow us to add cross-cutting logic in the future.
Context->setSourceManager(Result.SourceManager);
check(Result);
}
@@ -502,12 +489,11 @@ getCheckOptions(const ClangTidyOptions &Options,
return Factory.getCheckOptions();
}
std::vector<ClangTidyError>
runClangTidy(clang::tidy::ClangTidyContext &Context,
const CompilationDatabase &Compilations,
ArrayRef<std::string> InputFiles,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
bool EnableCheckProfile, llvm::StringRef StoreCheckProfile) {
void runClangTidy(clang::tidy::ClangTidyContext &Context,
const CompilationDatabase &Compilations,
ArrayRef<std::string> InputFiles,
llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS,
bool EnableCheckProfile, llvm::StringRef StoreCheckProfile) {
ClangTool Tool(Compilations, InputFiles,
std::make_shared<PCHContainerOperations>(), BaseFS);
@@ -529,15 +515,29 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
return AdjustedArgs;
};
// Remove plugins arguments.
ArgumentsAdjuster PluginArgumentsRemover =
[](const CommandLineArguments &Args, StringRef Filename) {
CommandLineArguments AdjustedArgs;
for (size_t I = 0, E = Args.size(); I < E; ++I) {
if (I + 4 < Args.size() && Args[I] == "-Xclang" &&
(Args[I + 1] == "-load" || Args[I + 1] == "-add-plugin" ||
StringRef(Args[I + 1]).startswith("-plugin-arg-")) &&
Args[I + 2] == "-Xclang") {
I += 3;
} else
AdjustedArgs.push_back(Args[I]);
}
return AdjustedArgs;
};
Tool.appendArgumentsAdjuster(PerFileExtraArgumentsInserter);
Tool.appendArgumentsAdjuster(getStripPluginsAdjuster());
Tool.appendArgumentsAdjuster(PluginArgumentsRemover);
Context.setEnableProfiling(EnableCheckProfile);
Context.setProfileStoragePrefix(StoreCheckProfile);
ClangTidyDiagnosticConsumer DiagConsumer(Context);
DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions(),
&DiagConsumer, /*ShouldOwnClient=*/false);
Context.setDiagnosticsEngine(&DE);
Tool.setDiagnosticConsumer(&DiagConsumer);
class ActionFactory : public FrontendActionFactory {
@@ -575,21 +575,19 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
ActionFactory Factory(Context);
Tool.run(&Factory);
return DiagConsumer.take();
}
void handleErrors(llvm::ArrayRef<ClangTidyError> Errors,
ClangTidyContext &Context, bool Fix,
void handleErrors(ClangTidyContext &Context, bool Fix,
unsigned &WarningsAsErrorsCount,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS) {
llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) {
ErrorReporter Reporter(Context, Fix, BaseFS);
llvm::vfs::FileSystem &FileSystem =
vfs::FileSystem &FileSystem =
*Reporter.getSourceManager().getFileManager().getVirtualFileSystem();
auto InitialWorkingDir = FileSystem.getCurrentWorkingDirectory();
if (!InitialWorkingDir)
llvm::report_fatal_error("Cannot get current working path.");
for (const ClangTidyError &Error : Errors) {
for (const ClangTidyError &Error : Context.getErrors()) {
if (!Error.BuildDirectory.empty()) {
// By default, the working directory of file system is the current
// clang-tidy running directory.

View File

@@ -230,13 +230,12 @@ getCheckOptions(const ClangTidyOptions &Options,
/// \param StoreCheckProfile If provided, and EnableCheckProfile is true,
/// the profile will not be output to stderr, but will instead be stored
/// as a JSON file in the specified directory.
std::vector<ClangTidyError>
runClangTidy(clang::tidy::ClangTidyContext &Context,
const tooling::CompilationDatabase &Compilations,
ArrayRef<std::string> InputFiles,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
bool EnableCheckProfile = false,
llvm::StringRef StoreCheckProfile = StringRef());
void runClangTidy(clang::tidy::ClangTidyContext &Context,
const tooling::CompilationDatabase &Compilations,
ArrayRef<std::string> InputFiles,
llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS,
bool EnableCheckProfile = false,
llvm::StringRef StoreCheckProfile = StringRef());
// FIXME: This interface will need to be significantly extended to be useful.
// FIXME: Implement confidence levels for displaying/fixing errors.
@@ -244,10 +243,9 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
/// \brief Displays the found \p Errors to the users. If \p Fix is true, \p
/// Errors containing fixes are automatically applied and reformatted. If no
/// clang-format configuration file is found, the given \P FormatStyle is used.
void handleErrors(llvm::ArrayRef<ClangTidyError> Errors,
ClangTidyContext &Context, bool Fix,
void handleErrors(ClangTidyContext &Context, bool Fix,
unsigned &WarningsAsErrorsCount,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS);
llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS);
/// \brief Serializes replacements into YAML and writes them to the specified
/// output stream.

View File

@@ -199,6 +199,10 @@ DiagnosticBuilder ClangTidyContext::diag(
return DiagEngine->Report(Loc, ID);
}
void ClangTidyContext::setDiagnosticsEngine(DiagnosticsEngine *Engine) {
DiagEngine = Engine;
}
void ClangTidyContext::setSourceManager(SourceManager *SourceMgr) {
DiagEngine->setSourceManager(SourceMgr);
}
@@ -255,6 +259,11 @@ bool ClangTidyContext::treatAsError(StringRef CheckName) const {
return WarningAsErrorFilter->contains(CheckName);
}
/// \brief Store a \c ClangTidyError.
void ClangTidyContext::storeError(const ClangTidyError &Error) {
Errors.push_back(Error);
}
StringRef ClangTidyContext::getCheckName(unsigned DiagnosticID) const {
llvm::DenseMap<unsigned, std::string>::const_iterator I =
CheckNamesByDiagnosticID.find(DiagnosticID);
@@ -267,7 +276,13 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer(
ClangTidyContext &Ctx, bool RemoveIncompatibleErrors)
: Context(Ctx), RemoveIncompatibleErrors(RemoveIncompatibleErrors),
LastErrorRelatesToUserCode(false), LastErrorPassesLineFilter(false),
LastErrorWasIgnored(false) {}
LastErrorWasIgnored(false) {
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
Diags = llvm::make_unique<DiagnosticsEngine>(
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts, this,
/*ShouldOwnClient=*/false);
Context.setDiagnosticsEngine(Diags.get());
}
void ClangTidyDiagnosticConsumer::finalizeLastError() {
if (!Errors.empty()) {
@@ -319,7 +334,7 @@ static bool IsNOLINTFound(StringRef NolintDirectiveText, StringRef Line,
return true;
}
static bool LineIsMarkedWithNOLINT(const SourceManager &SM, SourceLocation Loc,
static bool LineIsMarkedWithNOLINT(SourceManager &SM, SourceLocation Loc,
unsigned DiagID,
const ClangTidyContext &Context) {
bool Invalid;
@@ -365,8 +380,8 @@ static bool LineIsMarkedWithNOLINT(const SourceManager &SM, SourceLocation Loc,
return false;
}
static bool LineIsMarkedWithNOLINTinMacro(const SourceManager &SM,
SourceLocation Loc, unsigned DiagID,
static bool LineIsMarkedWithNOLINTinMacro(SourceManager &SM, SourceLocation Loc,
unsigned DiagID,
const ClangTidyContext &Context) {
while (true) {
if (LineIsMarkedWithNOLINT(SM, Loc, DiagID, Context))
@@ -385,7 +400,7 @@ void ClangTidyDiagnosticConsumer::HandleDiagnostic(
if (Info.getLocation().isValid() && DiagLevel != DiagnosticsEngine::Error &&
DiagLevel != DiagnosticsEngine::Fatal &&
LineIsMarkedWithNOLINTinMacro(Info.getSourceManager(),
LineIsMarkedWithNOLINTinMacro(Diags->getSourceManager(),
Info.getLocation(), Info.getID(),
Context)) {
++Context.Stats.ErrorsIgnoredNOLINT;
@@ -447,14 +462,14 @@ void ClangTidyDiagnosticConsumer::HandleDiagnostic(
Errors.back());
SmallString<100> Message;
Info.FormatDiagnostic(Message);
FullSourceLoc Loc;
if (Info.getLocation().isValid() && Info.hasSourceManager())
Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
FullSourceLoc Loc =
(Info.getLocation().isInvalid())
? FullSourceLoc()
: FullSourceLoc(Info.getLocation(), Info.getSourceManager());
Converter.emitDiagnostic(Loc, DiagLevel, Message, Info.getRanges(),
Info.getFixItHints());
if (Info.hasSourceManager())
checkFilters(Info.getLocation(), Info.getSourceManager());
checkFilters(Info.getLocation());
}
bool ClangTidyDiagnosticConsumer::passesLineFilter(StringRef FileName,
@@ -475,8 +490,7 @@ bool ClangTidyDiagnosticConsumer::passesLineFilter(StringRef FileName,
return false;
}
void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location,
const SourceManager &Sources) {
void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location) {
// Invalid location may mean a diagnostic in a command line, don't skip these.
if (!Location.isValid()) {
LastErrorRelatesToUserCode = true;
@@ -484,6 +498,7 @@ void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location,
return;
}
const SourceManager &Sources = Diags->getSourceManager();
if (!*Context.getOptions().SystemHeaders &&
Sources.isInSystemHeader(Location))
return;
@@ -519,7 +534,8 @@ llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() {
return HeaderFilter.get();
}
void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() {
void ClangTidyDiagnosticConsumer::removeIncompatibleErrors(
SmallVectorImpl<ClangTidyError> &Errors) const {
// Each error is modelled as the set of intervals in which it applies
// replacements. To detect overlapping replacements, we use a sweep line
// algorithm over these sets of intervals.
@@ -657,13 +673,18 @@ struct EqualClangTidyError {
};
} // end anonymous namespace
std::vector<ClangTidyError> ClangTidyDiagnosticConsumer::take() {
// Flushes the internal diagnostics buffer to the ClangTidyContext.
void ClangTidyDiagnosticConsumer::finish() {
finalizeLastError();
std::sort(Errors.begin(), Errors.end(), LessClangTidyError());
Errors.erase(std::unique(Errors.begin(), Errors.end(), EqualClangTidyError()),
Errors.end());
if (RemoveIncompatibleErrors)
removeIncompatibleErrors();
return std::move(Errors);
removeIncompatibleErrors(Errors);
for (const ClangTidyError &Error : Errors)
Context.storeError(Error);
Errors.clear();
}

View File

@@ -102,12 +102,6 @@ public:
/// \brief Initializes \c ClangTidyContext instance.
ClangTidyContext(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
bool AllowEnablingAnalyzerAlphaCheckers = false);
/// Sets the DiagnosticsEngine that diag() will emit diagnostics to.
// FIXME: this is required initialization, and should be a constructor param.
// Fix the context -> diag engine -> consumer -> context initialization cycle.
void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) {
this->DiagEngine = DiagEngine;
}
~ClangTidyContext();
@@ -166,6 +160,12 @@ public:
/// counters.
const ClangTidyStats &getStats() const { return Stats; }
/// \brief Returns all collected errors.
ArrayRef<ClangTidyError> getErrors() const { return Errors; }
/// \brief Clears collected errors.
void clearErrors() { Errors.clear(); }
/// \brief Control profile collection in clang-tidy.
void setEnableProfiling(bool Profile);
bool getEnableProfiling() const { return Profile; }
@@ -192,9 +192,18 @@ public:
}
private:
// Writes to Stats.
// Calls setDiagnosticsEngine() and storeError().
friend class ClangTidyDiagnosticConsumer;
friend class ClangTidyPluginAction;
/// \brief Sets the \c DiagnosticsEngine so that Diagnostics can be generated
/// correctly.
void setDiagnosticsEngine(DiagnosticsEngine *Engine);
/// \brief Store an \p Error.
void storeError(const ClangTidyError &Error);
std::vector<ClangTidyError> Errors;
DiagnosticsEngine *DiagEngine;
std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
@@ -234,12 +243,13 @@ public:
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) override;
// Retrieve the diagnostics that were captured.
std::vector<ClangTidyError> take();
/// \brief Flushes the internal diagnostics buffer to the ClangTidyContext.
void finish() override;
private:
void finalizeLastError();
void removeIncompatibleErrors();
void removeIncompatibleErrors(SmallVectorImpl<ClangTidyError> &Errors) const;
/// \brief Returns the \c HeaderFilter constructed for the options set in the
/// context.
@@ -247,12 +257,13 @@ private:
/// \brief Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter
/// according to the diagnostic \p Location.
void checkFilters(SourceLocation Location, const SourceManager& Sources);
void checkFilters(SourceLocation Location);
bool passesLineFilter(StringRef FileName, unsigned LineNumber) const;
ClangTidyContext &Context;
bool RemoveIncompatibleErrors;
std::vector<ClangTidyError> Errors;
std::unique_ptr<DiagnosticsEngine> Diags;
SmallVector<ClangTidyError, 8> Errors;
std::unique_ptr<llvm::Regex> HeaderFilter;
bool LastErrorRelatesToUserCode;
bool LastErrorPassesLineFilter;

View File

@@ -1,114 +0,0 @@
//===- ClangTidyForceLinker.h - clang-tidy --------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYFORCELINKER_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYFORCELINKER_H
#include "clang/Config/config.h"
#include "llvm/Support/Compiler.h"
namespace clang {
namespace tidy {
// This anchor is used to force the linker to link the CERTModule.
extern volatile int CERTModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED CERTModuleAnchorDestination =
CERTModuleAnchorSource;
// This anchor is used to force the linker to link the AbseilModule.
extern volatile int AbseilModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED AbseilModuleAnchorDestination =
AbseilModuleAnchorSource;
// This anchor is used to force the linker to link the BoostModule.
extern volatile int BoostModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED BoostModuleAnchorDestination =
BoostModuleAnchorSource;
// This anchor is used to force the linker to link the BugproneModule.
extern volatile int BugproneModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED BugproneModuleAnchorDestination =
BugproneModuleAnchorSource;
// This anchor is used to force the linker to link the LLVMModule.
extern volatile int LLVMModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED LLVMModuleAnchorDestination =
LLVMModuleAnchorSource;
// This anchor is used to force the linker to link the CppCoreGuidelinesModule.
extern volatile int CppCoreGuidelinesModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED CppCoreGuidelinesModuleAnchorDestination =
CppCoreGuidelinesModuleAnchorSource;
// This anchor is used to force the linker to link the FuchsiaModule.
extern volatile int FuchsiaModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED FuchsiaModuleAnchorDestination =
FuchsiaModuleAnchorSource;
// This anchor is used to force the linker to link the GoogleModule.
extern volatile int GoogleModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED GoogleModuleAnchorDestination =
GoogleModuleAnchorSource;
// This anchor is used to force the linker to link the AndroidModule.
extern volatile int AndroidModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED AndroidModuleAnchorDestination =
AndroidModuleAnchorSource;
// This anchor is used to force the linker to link the MiscModule.
extern volatile int MiscModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED MiscModuleAnchorDestination =
MiscModuleAnchorSource;
// This anchor is used to force the linker to link the ModernizeModule.
extern volatile int ModernizeModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED ModernizeModuleAnchorDestination =
ModernizeModuleAnchorSource;
#if CLANG_ENABLE_STATIC_ANALYZER
// This anchor is used to force the linker to link the MPIModule.
extern volatile int MPIModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED MPIModuleAnchorDestination =
MPIModuleAnchorSource;
#endif
// This anchor is used to force the linker to link the PerformanceModule.
extern volatile int PerformanceModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED PerformanceModuleAnchorDestination =
PerformanceModuleAnchorSource;
// This anchor is used to force the linker to link the PortabilityModule.
extern volatile int PortabilityModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED PortabilityModuleAnchorDestination =
PortabilityModuleAnchorSource;
// This anchor is used to force the linker to link the ReadabilityModule.
extern volatile int ReadabilityModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED ReadabilityModuleAnchorDestination =
ReadabilityModuleAnchorSource;
// This anchor is used to force the linker to link the ObjCModule.
extern volatile int ObjCModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED ObjCModuleAnchorDestination =
ObjCModuleAnchorSource;
// This anchor is used to force the linker to link the HICPPModule.
extern volatile int HICPPModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED HICPPModuleAnchorDestination =
HICPPModuleAnchorSource;
// This anchor is used to force the linker to link the ZirconModule.
extern volatile int ZirconModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED ZirconModuleAnchorDestination =
ZirconModuleAnchorSource;
} // namespace tidy
} // namespace clang
#endif

View File

@@ -204,11 +204,11 @@ FileOptionsProvider::FileOptionsProvider(
const ClangTidyGlobalOptions &GlobalOptions,
const ClangTidyOptions &DefaultOptions,
const ClangTidyOptions &OverrideOptions,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)
llvm::IntrusiveRefCntPtr<vfs::FileSystem> VFS)
: DefaultOptionsProvider(GlobalOptions, DefaultOptions),
OverrideOptions(OverrideOptions), FS(std::move(VFS)) {
if (!FS)
FS = llvm::vfs::getRealFileSystem();
FS = vfs::getRealFileSystem();
ConfigHandlers.emplace_back(".clang-tidy", parseConfiguration);
}

View File

@@ -10,12 +10,12 @@
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "clang/Basic/VirtualFileSystem.h"
#include <functional>
#include <map>
#include <string>
@@ -218,11 +218,10 @@ public:
///
/// If any of the \param OverrideOptions fields are set, they will override
/// whatever options are read from the configuration file.
FileOptionsProvider(
const ClangTidyGlobalOptions &GlobalOptions,
const ClangTidyOptions &DefaultOptions,
const ClangTidyOptions &OverrideOptions,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr);
FileOptionsProvider(const ClangTidyGlobalOptions &GlobalOptions,
const ClangTidyOptions &DefaultOptions,
const ClangTidyOptions &OverrideOptions,
llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS = nullptr);
/// \brief Initializes the \c FileOptionsProvider instance with a custom set
/// of configuration file handlers.
@@ -256,7 +255,7 @@ protected:
llvm::StringMap<OptionsSource> CachedOptions;
ClangTidyOptions OverrideOptions;
ConfigFileHandlers ConfigHandlers;
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS;
};
/// \brief Parses LineFilter from JSON and stores it to the \p Options.

View File

@@ -1,62 +0,0 @@
//===- AbseilMatcher.h - clang-tidy ---------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include <algorithm>
namespace clang {
namespace ast_matchers {
/// Matches AST nodes that were found within Abseil files.
///
/// Example matches Y but not X
/// (matcher = cxxRecordDecl(isInAbseilFile())
/// \code
/// #include "absl/strings/internal-file.h"
/// class X {};
/// \endcode
/// absl/strings/internal-file.h:
/// \code
/// class Y {};
/// \endcode
///
/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>,
/// Matcher<NestedNameSpecifierLoc>
AST_POLYMORPHIC_MATCHER(
isInAbseilFile, AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc,
NestedNameSpecifierLoc)) {
auto &SourceManager = Finder->getASTContext().getSourceManager();
SourceLocation Loc = SourceManager.getSpellingLoc(Node.getBeginLoc());
if (Loc.isInvalid())
return false;
const FileEntry *FileEntry =
SourceManager.getFileEntryForID(SourceManager.getFileID(Loc));
if (!FileEntry)
return false;
// Determine whether filepath contains "absl/[absl-library]" substring, where
// [absl-library] is AbseilLibraries list entry.
StringRef Path = FileEntry->getName();
static constexpr llvm::StringLiteral AbslPrefix("absl/");
size_t PrefixPosition = Path.find(AbslPrefix);
if (PrefixPosition == StringRef::npos)
return false;
Path = Path.drop_front(PrefixPosition + AbslPrefix.size());
static const char *AbseilLibraries[] = {
"algorithm", "base", "container", "debugging", "flags",
"hash", "iterator", "memory", "meta", "numeric",
"random", "strings", "synchronization", "time", "types",
"utility"};
return std::any_of(
std::begin(AbseilLibraries), std::end(AbseilLibraries),
[&](const char *Library) { return Path.startswith(Library); });
}
} // namespace ast_matchers
} // namespace clang

View File

@@ -10,18 +10,7 @@
#include "../ClangTidy.h"
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
#include "DurationComparisonCheck.h"
#include "DurationDivisionCheck.h"
#include "DurationFactoryFloatCheck.h"
#include "DurationFactoryScaleCheck.h"
#include "DurationSubtractionCheck.h"
#include "FasterStrsplitDelimiterCheck.h"
#include "NoInternalDependenciesCheck.h"
#include "NoNamespaceCheck.h"
#include "RedundantStrcatCallsCheck.h"
#include "StringFindStartswithCheck.h"
#include "StrCatAppendCheck.h"
#include "UpgradeDurationConversionsCheck.h"
namespace clang {
namespace tidy {
@@ -30,29 +19,8 @@ namespace abseil {
class AbseilModule : public ClangTidyModule {
public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
CheckFactories.registerCheck<DurationComparisonCheck>(
"abseil-duration-comparison");
CheckFactories.registerCheck<DurationDivisionCheck>(
"abseil-duration-division");
CheckFactories.registerCheck<DurationFactoryFloatCheck>(
"abseil-duration-factory-float");
CheckFactories.registerCheck<DurationFactoryScaleCheck>(
"abseil-duration-factory-scale");
CheckFactories.registerCheck<DurationSubtractionCheck>(
"abseil-duration-subtraction");
CheckFactories.registerCheck<FasterStrsplitDelimiterCheck>(
"abseil-faster-strsplit-delimiter");
CheckFactories.registerCheck<NoInternalDependenciesCheck>(
"abseil-no-internal-dependencies");
CheckFactories.registerCheck<NoNamespaceCheck>("abseil-no-namespace");
CheckFactories.registerCheck<RedundantStrcatCallsCheck>(
"abseil-redundant-strcat-calls");
CheckFactories.registerCheck<StrCatAppendCheck>(
"abseil-str-cat-append");
CheckFactories.registerCheck<StringFindStartswithCheck>(
"abseil-string-find-startswith");
CheckFactories.registerCheck<UpgradeDurationConversionsCheck>(
"abseil-upgrade-duration-conversions");
}
};

View File

@@ -2,19 +2,7 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTidyAbseilModule
AbseilTidyModule.cpp
DurationComparisonCheck.cpp
DurationDivisionCheck.cpp
DurationFactoryFloatCheck.cpp
DurationFactoryScaleCheck.cpp
DurationRewriter.cpp
DurationSubtractionCheck.cpp
FasterStrsplitDelimiterCheck.cpp
NoInternalDependenciesCheck.cpp
NoNamespaceCheck.cpp
RedundantStrcatCallsCheck.cpp
StrCatAppendCheck.cpp
StringFindStartswithCheck.cpp
UpgradeDurationConversionsCheck.cpp
LINK_LIBS
clangAST
@@ -23,5 +11,4 @@ add_clang_library(clangTidyAbseilModule
clangLex
clangTidy
clangTidyUtils
clangTooling
)

View File

@@ -1,85 +0,0 @@
//===--- DurationComparisonCheck.cpp - clang-tidy -------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DurationComparisonCheck.h"
#include "DurationRewriter.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/FixIt.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace abseil {
/// Return `true` if `E` is a either: not a macro at all; or an argument to
/// one. In the latter case, we should still transform it.
static bool IsValidMacro(const MatchFinder::MatchResult &Result,
const Expr *E) {
if (!E->getBeginLoc().isMacroID())
return true;
SourceLocation Loc = E->getBeginLoc();
// We want to get closer towards the initial macro typed into the source only
// if the location is being expanded as a macro argument.
while (Result.SourceManager->isMacroArgExpansion(Loc)) {
// We are calling getImmediateMacroCallerLoc, but note it is essentially
// equivalent to calling getImmediateSpellingLoc in this context according
// to Clang implementation. We are not calling getImmediateSpellingLoc
// because Clang comment says it "should not generally be used by clients."
Loc = Result.SourceManager->getImmediateMacroCallerLoc(Loc);
}
return !Loc.isMacroID();
}
void DurationComparisonCheck::registerMatchers(MatchFinder *Finder) {
auto Matcher =
binaryOperator(anyOf(hasOperatorName(">"), hasOperatorName(">="),
hasOperatorName("=="), hasOperatorName("<="),
hasOperatorName("<")),
hasEitherOperand(ignoringImpCasts(callExpr(
callee(functionDecl(DurationConversionFunction())
.bind("function_decl"))))))
.bind("binop");
Finder->addMatcher(Matcher, this);
}
void DurationComparisonCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Binop = Result.Nodes.getNodeAs<BinaryOperator>("binop");
llvm::Optional<DurationScale> Scale = getScaleForInverse(
Result.Nodes.getNodeAs<FunctionDecl>("function_decl")->getName());
if (!Scale)
return;
// In most cases, we'll only need to rewrite one of the sides, but we also
// want to handle the case of rewriting both sides. This is much simpler if
// we unconditionally try and rewrite both, and let the rewriter determine
// if nothing needs to be done.
if (!IsValidMacro(Result, Binop->getLHS()) ||
!IsValidMacro(Result, Binop->getRHS()))
return;
std::string LhsReplacement =
rewriteExprFromNumberToDuration(Result, *Scale, Binop->getLHS());
std::string RhsReplacement =
rewriteExprFromNumberToDuration(Result, *Scale, Binop->getRHS());
diag(Binop->getBeginLoc(), "perform comparison in the duration domain")
<< FixItHint::CreateReplacement(Binop->getSourceRange(),
(llvm::Twine(LhsReplacement) + " " +
Binop->getOpcodeStr() + " " +
RhsReplacement)
.str());
}
} // namespace abseil
} // namespace tidy
} // namespace clang

View File

@@ -1,36 +0,0 @@
//===--- DurationComparisonCheck.h - clang-tidy -----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONCOMPARISONCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONCOMPARISONCHECK_H
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
namespace abseil {
/// Prefer comparison in the absl::Duration domain instead of the numeric
/// domain.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-duration-comparison.html
class DurationComparisonCheck : public ClangTidyCheck {
public:
DurationComparisonCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace abseil
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONCOMPARISONCHECK_H

View File

@@ -1,59 +0,0 @@
//===--- DurationDivisionCheck.cpp - clang-tidy----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DurationDivisionCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
namespace clang {
namespace tidy {
namespace abseil {
using namespace clang::ast_matchers;
void DurationDivisionCheck::registerMatchers(MatchFinder *finder) {
if (!getLangOpts().CPlusPlus)
return;
const auto DurationExpr =
expr(hasType(cxxRecordDecl(hasName("::absl::Duration"))));
finder->addMatcher(
implicitCastExpr(
hasSourceExpression(ignoringParenCasts(
cxxOperatorCallExpr(hasOverloadedOperatorName("/"),
hasArgument(0, DurationExpr),
hasArgument(1, DurationExpr))
.bind("OpCall"))),
hasImplicitDestinationType(qualType(unless(isInteger()))),
unless(hasParent(cxxStaticCastExpr())),
unless(hasParent(cStyleCastExpr())),
unless(isInTemplateInstantiation())),
this);
}
void DurationDivisionCheck::check(const MatchFinder::MatchResult &result) {
const auto *OpCall = result.Nodes.getNodeAs<CXXOperatorCallExpr>("OpCall");
diag(OpCall->getOperatorLoc(),
"operator/ on absl::Duration objects performs integer division; "
"did you mean to use FDivDuration()?")
<< FixItHint::CreateInsertion(OpCall->getBeginLoc(),
"absl::FDivDuration(")
<< FixItHint::CreateReplacement(
SourceRange(OpCall->getOperatorLoc(), OpCall->getOperatorLoc()),
", ")
<< FixItHint::CreateInsertion(
Lexer::getLocForEndOfToken(
result.SourceManager->getSpellingLoc(OpCall->getEndLoc()), 0,
*result.SourceManager, result.Context->getLangOpts()),
")");
}
} // namespace abseil
} // namespace tidy
} // namespace clang

View File

@@ -1,35 +0,0 @@
//===--- DurationDivisionCheck.h - clang-tidy--------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONDIVISIONCHECK_H_
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONDIVISIONCHECK_H_
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
namespace abseil {
// Find potential incorrect uses of integer division of absl::Duration objects.
//
// For the user-facing documentation see:
// http://clang.llvm.org/extra/clang-tidy/checks/abseil-duration-division.html
class DurationDivisionCheck : public ClangTidyCheck {
public:
using ClangTidyCheck::ClangTidyCheck;
void registerMatchers(ast_matchers::MatchFinder *finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &result) override;
};
} // namespace abseil
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONDIVISIONCHECK_H_

View File

@@ -1,72 +0,0 @@
//===--- DurationFactoryFloatCheck.cpp - clang-tidy -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DurationFactoryFloatCheck.h"
#include "DurationRewriter.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/FixIt.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace abseil {
// Returns `true` if `Range` is inside a macro definition.
static bool InsideMacroDefinition(const MatchFinder::MatchResult &Result,
SourceRange Range) {
return !clang::Lexer::makeFileCharRange(
clang::CharSourceRange::getCharRange(Range),
*Result.SourceManager, Result.Context->getLangOpts())
.isValid();
}
void DurationFactoryFloatCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
callExpr(callee(functionDecl(DurationFactoryFunction())),
hasArgument(0, anyOf(cxxStaticCastExpr(hasDestinationType(
realFloatingPointType())),
cStyleCastExpr(hasDestinationType(
realFloatingPointType())),
cxxFunctionalCastExpr(hasDestinationType(
realFloatingPointType())),
floatLiteral())))
.bind("call"),
this);
}
void DurationFactoryFloatCheck::check(const MatchFinder::MatchResult &Result) {
const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>("call");
// Don't try and replace things inside of macro definitions.
if (InsideMacroDefinition(Result, MatchedCall->getSourceRange()))
return;
const Expr *Arg = MatchedCall->getArg(0)->IgnoreImpCasts();
// Arguments which are macros are ignored.
if (Arg->getBeginLoc().isMacroID())
return;
llvm::Optional<std::string> SimpleArg = stripFloatCast(Result, *Arg);
if (!SimpleArg)
SimpleArg = stripFloatLiteralFraction(Result, *Arg);
if (SimpleArg) {
diag(MatchedCall->getBeginLoc(),
(llvm::Twine("use the integer version of absl::") +
MatchedCall->getDirectCallee()->getName())
.str())
<< FixItHint::CreateReplacement(Arg->getSourceRange(), *SimpleArg);
}
}
} // namespace abseil
} // namespace tidy
} // namespace clang

View File

@@ -1,38 +0,0 @@
//===--- DurationFactoryFloatCheck.h - clang-tidy ---------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONFACTORYFLOATCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONFACTORYFLOATCHECK_H
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
namespace abseil {
/// This check finds cases where `Duration` factories are being called with
/// floating point arguments, but could be called using integer arguments.
/// It handles explicit casts and floating point literals with no fractional
/// component.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-duration-factory-float.html
class DurationFactoryFloatCheck : public ClangTidyCheck {
public:
DurationFactoryFloatCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace abseil
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONFACTORYFLOATCHECK_H

View File

@@ -1,235 +0,0 @@
//===--- DurationFactoryScaleCheck.cpp - clang-tidy -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DurationFactoryScaleCheck.h"
#include "DurationRewriter.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/FixIt.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace abseil {
// Given the name of a duration factory function, return the appropriate
// `DurationScale` for that factory. If no factory can be found for
// `FactoryName`, return `None`.
static llvm::Optional<DurationScale>
getScaleForFactory(llvm::StringRef FactoryName) {
static const std::unordered_map<std::string, DurationScale> ScaleMap(
{{"Nanoseconds", DurationScale::Nanoseconds},
{"Microseconds", DurationScale::Microseconds},
{"Milliseconds", DurationScale::Milliseconds},
{"Seconds", DurationScale::Seconds},
{"Minutes", DurationScale::Minutes},
{"Hours", DurationScale::Hours}});
auto ScaleIter = ScaleMap.find(FactoryName);
if (ScaleIter == ScaleMap.end())
return llvm::None;
return ScaleIter->second;
}
// Given either an integer or float literal, return its value.
// One and only one of `IntLit` and `FloatLit` should be provided.
static double GetValue(const IntegerLiteral *IntLit,
const FloatingLiteral *FloatLit) {
if (IntLit)
return IntLit->getValue().getLimitedValue();
assert(FloatLit != nullptr && "Neither IntLit nor FloatLit set");
return FloatLit->getValueAsApproximateDouble();
}
// Given the scale of a duration and a `Multiplier`, determine if `Multiplier`
// would produce a new scale. If so, return a tuple containing the new scale
// and a suitable Multipler for that scale, otherwise `None`.
static llvm::Optional<std::tuple<DurationScale, double>>
GetNewScaleSingleStep(DurationScale OldScale, double Multiplier) {
switch (OldScale) {
case DurationScale::Hours:
if (Multiplier <= 1.0 / 60.0)
return std::make_tuple(DurationScale::Minutes, Multiplier * 60.0);
break;
case DurationScale::Minutes:
if (Multiplier >= 60.0)
return std::make_tuple(DurationScale::Hours, Multiplier / 60.0);
if (Multiplier <= 1.0 / 60.0)
return std::make_tuple(DurationScale::Seconds, Multiplier * 60.0);
break;
case DurationScale::Seconds:
if (Multiplier >= 60.0)
return std::make_tuple(DurationScale::Minutes, Multiplier / 60.0);
if (Multiplier <= 1e-3)
return std::make_tuple(DurationScale::Milliseconds, Multiplier * 1e3);
break;
case DurationScale::Milliseconds:
if (Multiplier >= 1e3)
return std::make_tuple(DurationScale::Seconds, Multiplier / 1e3);
if (Multiplier <= 1e-3)
return std::make_tuple(DurationScale::Microseconds, Multiplier * 1e3);
break;
case DurationScale::Microseconds:
if (Multiplier >= 1e3)
return std::make_tuple(DurationScale::Milliseconds, Multiplier / 1e3);
if (Multiplier <= 1e-3)
return std::make_tuple(DurationScale::Nanoseconds, Multiplier * 1e-3);
break;
case DurationScale::Nanoseconds:
if (Multiplier >= 1e3)
return std::make_tuple(DurationScale::Microseconds, Multiplier / 1e3);
break;
}
return llvm::None;
}
// Given the scale of a duration and a `Multiplier`, determine if `Multiplier`
// would produce a new scale. If so, return it, otherwise `None`.
static llvm::Optional<DurationScale> GetNewScale(DurationScale OldScale,
double Multiplier) {
while (Multiplier != 1.0) {
llvm::Optional<std::tuple<DurationScale, double>> result =
GetNewScaleSingleStep(OldScale, Multiplier);
if (!result)
break;
if (std::get<1>(*result) == 1.0)
return std::get<0>(*result);
Multiplier = std::get<1>(*result);
OldScale = std::get<0>(*result);
}
return llvm::None;
}
void DurationFactoryScaleCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
callExpr(
callee(functionDecl(DurationFactoryFunction()).bind("call_decl")),
hasArgument(
0,
ignoringImpCasts(anyOf(
cxxFunctionalCastExpr(
hasDestinationType(
anyOf(isInteger(), realFloatingPointType())),
hasSourceExpression(initListExpr())),
integerLiteral(equals(0)), floatLiteral(equals(0.0)),
binaryOperator(hasOperatorName("*"),
hasEitherOperand(ignoringImpCasts(
anyOf(integerLiteral(), floatLiteral()))))
.bind("mult_binop"),
binaryOperator(hasOperatorName("/"), hasRHS(floatLiteral()))
.bind("div_binop")))))
.bind("call"),
this);
}
void DurationFactoryScaleCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
// Don't try to replace things inside of macro definitions.
if (Call->getExprLoc().isMacroID())
return;
const Expr *Arg = Call->getArg(0)->IgnoreParenImpCasts();
// Arguments which are macros are ignored.
if (Arg->getBeginLoc().isMacroID())
return;
// We first handle the cases of literal zero (both float and integer).
if (IsLiteralZero(Result, *Arg)) {
diag(Call->getBeginLoc(),
"use ZeroDuration() for zero-length time intervals")
<< FixItHint::CreateReplacement(Call->getSourceRange(),
"absl::ZeroDuration()");
return;
}
const auto *CallDecl = Result.Nodes.getNodeAs<FunctionDecl>("call_decl");
llvm::Optional<DurationScale> MaybeScale =
getScaleForFactory(CallDecl->getName());
if (!MaybeScale)
return;
DurationScale Scale = *MaybeScale;
const Expr *Remainder;
llvm::Optional<DurationScale> NewScale;
// We next handle the cases of multiplication and division.
if (const auto *MultBinOp =
Result.Nodes.getNodeAs<BinaryOperator>("mult_binop")) {
// For multiplication, we need to look at both operands, and consider the
// cases where a user is multiplying by something such as 1e-3.
// First check the LHS
const auto *IntLit = llvm::dyn_cast<IntegerLiteral>(MultBinOp->getLHS());
const auto *FloatLit = llvm::dyn_cast<FloatingLiteral>(MultBinOp->getLHS());
if (IntLit || FloatLit) {
NewScale = GetNewScale(Scale, GetValue(IntLit, FloatLit));
if (NewScale)
Remainder = MultBinOp->getRHS();
}
// If we weren't able to scale based on the LHS, check the RHS
if (!NewScale) {
IntLit = llvm::dyn_cast<IntegerLiteral>(MultBinOp->getRHS());
FloatLit = llvm::dyn_cast<FloatingLiteral>(MultBinOp->getRHS());
if (IntLit || FloatLit) {
NewScale = GetNewScale(Scale, GetValue(IntLit, FloatLit));
if (NewScale)
Remainder = MultBinOp->getLHS();
}
}
} else if (const auto *DivBinOp =
Result.Nodes.getNodeAs<BinaryOperator>("div_binop")) {
// We next handle division.
// For division, we only check the RHS.
const auto *FloatLit = llvm::dyn_cast<FloatingLiteral>(DivBinOp->getRHS());
llvm::Optional<DurationScale> NewScale =
GetNewScale(Scale, 1.0 / FloatLit->getValueAsApproximateDouble());
if (NewScale) {
const Expr *Remainder = DivBinOp->getLHS();
// We've found an appropriate scaling factor and the new scale, so output
// the relevant fix.
diag(Call->getBeginLoc(), "internal duration scaling can be removed")
<< FixItHint::CreateReplacement(
Call->getSourceRange(),
(llvm::Twine(getFactoryForScale(*NewScale)) + "(" +
tooling::fixit::getText(*Remainder, *Result.Context) + ")")
.str());
}
}
if (NewScale) {
assert(Remainder && "No remainder found");
// We've found an appropriate scaling factor and the new scale, so output
// the relevant fix.
diag(Call->getBeginLoc(), "internal duration scaling can be removed")
<< FixItHint::CreateReplacement(
Call->getSourceRange(),
(llvm::Twine(getFactoryForScale(*NewScale)) + "(" +
tooling::fixit::getText(*Remainder, *Result.Context) + ")")
.str());
}
return;
}
} // namespace abseil
} // namespace tidy
} // namespace clang

View File

@@ -1,38 +0,0 @@
//===--- DurationFactoryScaleCheck.h - clang-tidy ---------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONFACTORYSCALECHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONFACTORYSCALECHECK_H
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
namespace abseil {
/// This check finds cases where the incorrect `Duration` factory function is
/// being used by looking for scaling constants inside the factory argument
/// and suggesting a more appropriate factory. It also looks for the special
/// case of zero and suggests `ZeroDuration()`.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-duration-factory-scale.html
class DurationFactoryScaleCheck : public ClangTidyCheck {
public:
DurationFactoryScaleCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace abseil
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONFACTORYSCALECHECK_H

View File

@@ -1,221 +0,0 @@
//===--- DurationRewriter.cpp - clang-tidy --------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DurationRewriter.h"
#include "clang/Tooling/FixIt.h"
#include "llvm/ADT/IndexedMap.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace abseil {
struct DurationScale2IndexFunctor {
using argument_type = DurationScale;
unsigned operator()(DurationScale Scale) const {
return static_cast<unsigned>(Scale);
}
};
/// Returns an integer if the fractional part of a `FloatingLiteral` is `0`.
static llvm::Optional<llvm::APSInt>
truncateIfIntegral(const FloatingLiteral &FloatLiteral) {
double Value = FloatLiteral.getValueAsApproximateDouble();
if (std::fmod(Value, 1) == 0) {
if (Value >= static_cast<double>(1u << 31))
return llvm::None;
return llvm::APSInt::get(static_cast<int64_t>(Value));
}
return llvm::None;
}
const std::pair<llvm::StringRef, llvm::StringRef> &
getInverseForScale(DurationScale Scale) {
static const llvm::IndexedMap<std::pair<llvm::StringRef, llvm::StringRef>,
DurationScale2IndexFunctor>
InverseMap = []() {
// TODO: Revisit the immediately invoked lamba technique when
// IndexedMap gets an initializer list constructor.
llvm::IndexedMap<std::pair<llvm::StringRef, llvm::StringRef>,
DurationScale2IndexFunctor>
InverseMap;
InverseMap.resize(6);
InverseMap[DurationScale::Hours] =
std::make_pair("::absl::ToDoubleHours", "::absl::ToInt64Hours");
InverseMap[DurationScale::Minutes] =
std::make_pair("::absl::ToDoubleMinutes", "::absl::ToInt64Minutes");
InverseMap[DurationScale::Seconds] =
std::make_pair("::absl::ToDoubleSeconds", "::absl::ToInt64Seconds");
InverseMap[DurationScale::Milliseconds] = std::make_pair(
"::absl::ToDoubleMilliseconds", "::absl::ToInt64Milliseconds");
InverseMap[DurationScale::Microseconds] = std::make_pair(
"::absl::ToDoubleMicroseconds", "::absl::ToInt64Microseconds");
InverseMap[DurationScale::Nanoseconds] = std::make_pair(
"::absl::ToDoubleNanoseconds", "::absl::ToInt64Nanoseconds");
return InverseMap;
}();
return InverseMap[Scale];
}
/// If `Node` is a call to the inverse of `Scale`, return that inverse's
/// argument, otherwise None.
static llvm::Optional<std::string>
rewriteInverseDurationCall(const MatchFinder::MatchResult &Result,
DurationScale Scale, const Expr &Node) {
const std::pair<llvm::StringRef, llvm::StringRef> &InverseFunctions =
getInverseForScale(Scale);
if (const auto *MaybeCallArg = selectFirst<const Expr>(
"e",
match(callExpr(callee(functionDecl(hasAnyName(
InverseFunctions.first, InverseFunctions.second))),
hasArgument(0, expr().bind("e"))),
Node, *Result.Context))) {
return tooling::fixit::getText(*MaybeCallArg, *Result.Context).str();
}
return llvm::None;
}
/// Returns the factory function name for a given `Scale`.
llvm::StringRef getFactoryForScale(DurationScale Scale) {
switch (Scale) {
case DurationScale::Hours:
return "absl::Hours";
case DurationScale::Minutes:
return "absl::Minutes";
case DurationScale::Seconds:
return "absl::Seconds";
case DurationScale::Milliseconds:
return "absl::Milliseconds";
case DurationScale::Microseconds:
return "absl::Microseconds";
case DurationScale::Nanoseconds:
return "absl::Nanoseconds";
}
llvm_unreachable("unknown scaling factor");
}
/// Returns `true` if `Node` is a value which evaluates to a literal `0`.
bool IsLiteralZero(const MatchFinder::MatchResult &Result, const Expr &Node) {
auto ZeroMatcher =
anyOf(integerLiteral(equals(0)), floatLiteral(equals(0.0)));
// Check to see if we're using a zero directly.
if (selectFirst<const clang::Expr>(
"val", match(expr(ignoringImpCasts(ZeroMatcher)).bind("val"), Node,
*Result.Context)) != nullptr)
return true;
// Now check to see if we're using a functional cast with a scalar
// initializer expression, e.g. `int{0}`.
if (selectFirst<const clang::Expr>(
"val", match(cxxFunctionalCastExpr(
hasDestinationType(
anyOf(isInteger(), realFloatingPointType())),
hasSourceExpression(initListExpr(
hasInit(0, ignoringParenImpCasts(ZeroMatcher)))))
.bind("val"),
Node, *Result.Context)) != nullptr)
return true;
return false;
}
llvm::Optional<std::string>
stripFloatCast(const ast_matchers::MatchFinder::MatchResult &Result,
const Expr &Node) {
if (const Expr *MaybeCastArg = selectFirst<const Expr>(
"cast_arg",
match(expr(anyOf(cxxStaticCastExpr(
hasDestinationType(realFloatingPointType()),
hasSourceExpression(expr().bind("cast_arg"))),
cStyleCastExpr(
hasDestinationType(realFloatingPointType()),
hasSourceExpression(expr().bind("cast_arg"))),
cxxFunctionalCastExpr(
hasDestinationType(realFloatingPointType()),
hasSourceExpression(expr().bind("cast_arg"))))),
Node, *Result.Context)))
return tooling::fixit::getText(*MaybeCastArg, *Result.Context).str();
return llvm::None;
}
llvm::Optional<std::string>
stripFloatLiteralFraction(const MatchFinder::MatchResult &Result,
const Expr &Node) {
if (const auto *LitFloat = llvm::dyn_cast<FloatingLiteral>(&Node))
// Attempt to simplify a `Duration` factory call with a literal argument.
if (llvm::Optional<llvm::APSInt> IntValue = truncateIfIntegral(*LitFloat))
return IntValue->toString(/*radix=*/10);
return llvm::None;
}
std::string simplifyDurationFactoryArg(const MatchFinder::MatchResult &Result,
const Expr &Node) {
// Check for an explicit cast to `float` or `double`.
if (llvm::Optional<std::string> MaybeArg = stripFloatCast(Result, Node))
return *MaybeArg;
// Check for floats without fractional components.
if (llvm::Optional<std::string> MaybeArg =
stripFloatLiteralFraction(Result, Node))
return *MaybeArg;
// We couldn't simplify any further, so return the argument text.
return tooling::fixit::getText(Node, *Result.Context).str();
}
llvm::Optional<DurationScale> getScaleForInverse(llvm::StringRef Name) {
static const llvm::StringMap<DurationScale> ScaleMap(
{{"ToDoubleHours", DurationScale::Hours},
{"ToInt64Hours", DurationScale::Hours},
{"ToDoubleMinutes", DurationScale::Minutes},
{"ToInt64Minutes", DurationScale::Minutes},
{"ToDoubleSeconds", DurationScale::Seconds},
{"ToInt64Seconds", DurationScale::Seconds},
{"ToDoubleMilliseconds", DurationScale::Milliseconds},
{"ToInt64Milliseconds", DurationScale::Milliseconds},
{"ToDoubleMicroseconds", DurationScale::Microseconds},
{"ToInt64Microseconds", DurationScale::Microseconds},
{"ToDoubleNanoseconds", DurationScale::Nanoseconds},
{"ToInt64Nanoseconds", DurationScale::Nanoseconds}});
auto ScaleIter = ScaleMap.find(std::string(Name));
if (ScaleIter == ScaleMap.end())
return llvm::None;
return ScaleIter->second;
}
std::string rewriteExprFromNumberToDuration(
const ast_matchers::MatchFinder::MatchResult &Result, DurationScale Scale,
const Expr *Node) {
const Expr &RootNode = *Node->IgnoreParenImpCasts();
// First check to see if we can undo a complimentary function call.
if (llvm::Optional<std::string> MaybeRewrite =
rewriteInverseDurationCall(Result, Scale, RootNode))
return *MaybeRewrite;
if (IsLiteralZero(Result, RootNode))
return std::string("absl::ZeroDuration()");
return (llvm::Twine(getFactoryForScale(Scale)) + "(" +
simplifyDurationFactoryArg(Result, RootNode) + ")")
.str();
}
} // namespace abseil
} // namespace tidy
} // namespace clang

View File

@@ -1,102 +0,0 @@
//===--- DurationRewriter.h - clang-tidy ------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONREWRITER_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONREWRITER_H
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include <cinttypes>
namespace clang {
namespace tidy {
namespace abseil {
/// Duration factory and conversion scales
enum class DurationScale : std::uint8_t {
Hours = 0,
Minutes,
Seconds,
Milliseconds,
Microseconds,
Nanoseconds,
};
/// Given a `Scale`, return the appropriate factory function call for
/// constructing a `Duration` for that scale.
llvm::StringRef getFactoryForScale(DurationScale Scale);
// Determine if `Node` represents a literal floating point or integral zero.
bool IsLiteralZero(const ast_matchers::MatchFinder::MatchResult &Result,
const Expr &Node);
/// Possibly strip a floating point cast expression.
///
/// If `Node` represents an explicit cast to a floating point type, return
/// the textual context of the cast argument, otherwise `None`.
llvm::Optional<std::string>
stripFloatCast(const ast_matchers::MatchFinder::MatchResult &Result,
const Expr &Node);
/// Possibly remove the fractional part of a floating point literal.
///
/// If `Node` represents a floating point literal with a zero fractional part,
/// return the textual context of the integral part, otherwise `None`.
llvm::Optional<std::string>
stripFloatLiteralFraction(const ast_matchers::MatchFinder::MatchResult &Result,
const Expr &Node);
/// Possibly further simplify a duration factory function's argument, without
/// changing the scale of the factory function. Return that simplification or
/// the text of the argument if no simplification is possible.
std::string
simplifyDurationFactoryArg(const ast_matchers::MatchFinder::MatchResult &Result,
const Expr &Node);
/// Given the name of an inverse Duration function (e.g., `ToDoubleSeconds`),
/// return its `DurationScale`, or `None` if a match is not found.
llvm::Optional<DurationScale> getScaleForInverse(llvm::StringRef Name);
/// Given a `Scale` return the fully qualified inverse functions for it.
/// The first returned value is the inverse for `double`, and the second
/// returned value is the inverse for `int64`.
const std::pair<llvm::StringRef, llvm::StringRef> &
getInverseForScale(DurationScale Scale);
/// Assuming `Node` has type `double` or `int` representing a time interval of
/// `Scale`, return the expression to make it a suitable `Duration`.
std::string rewriteExprFromNumberToDuration(
const ast_matchers::MatchFinder::MatchResult &Result, DurationScale Scale,
const Expr *Node);
AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<FunctionDecl>,
DurationConversionFunction) {
using namespace clang::ast_matchers;
return functionDecl(
hasAnyName("::absl::ToDoubleHours", "::absl::ToDoubleMinutes",
"::absl::ToDoubleSeconds", "::absl::ToDoubleMilliseconds",
"::absl::ToDoubleMicroseconds", "::absl::ToDoubleNanoseconds",
"::absl::ToInt64Hours", "::absl::ToInt64Minutes",
"::absl::ToInt64Seconds", "::absl::ToInt64Milliseconds",
"::absl::ToInt64Microseconds", "::absl::ToInt64Nanoseconds"));
}
AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<FunctionDecl>,
DurationFactoryFunction) {
using namespace clang::ast_matchers;
return functionDecl(hasAnyName("::absl::Nanoseconds", "::absl::Microseconds",
"::absl::Milliseconds", "::absl::Seconds",
"::absl::Minutes", "::absl::Hours"));
}
} // namespace abseil
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONCOMPARISONCHECK_H

View File

@@ -1,61 +0,0 @@
//===--- DurationSubtractionCheck.cpp - clang-tidy ------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DurationSubtractionCheck.h"
#include "DurationRewriter.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/FixIt.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace abseil {
void DurationSubtractionCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
binaryOperator(
hasOperatorName("-"),
hasLHS(callExpr(callee(functionDecl(DurationConversionFunction())
.bind("function_decl")),
hasArgument(0, expr().bind("lhs_arg")))))
.bind("binop"),
this);
}
void DurationSubtractionCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Binop = Result.Nodes.getNodeAs<BinaryOperator>("binop");
const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("function_decl");
// Don't try to replace things inside of macro definitions.
if (Binop->getExprLoc().isMacroID() || Binop->getExprLoc().isInvalid())
return;
llvm::Optional<DurationScale> Scale = getScaleForInverse(FuncDecl->getName());
if (!Scale)
return;
std::string RhsReplacement =
rewriteExprFromNumberToDuration(Result, *Scale, Binop->getRHS());
const Expr *LhsArg = Result.Nodes.getNodeAs<Expr>("lhs_arg");
diag(Binop->getBeginLoc(), "perform subtraction in the duration domain")
<< FixItHint::CreateReplacement(
Binop->getSourceRange(),
(llvm::Twine("absl::") + FuncDecl->getName() + "(" +
tooling::fixit::getText(*LhsArg, *Result.Context) + " - " +
RhsReplacement + ")")
.str());
}
} // namespace abseil
} // namespace tidy
} // namespace clang

View File

@@ -1,36 +0,0 @@
//===--- DurationSubtractionCheck.h - clang-tidy ----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONSUBTRACTIONCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONSUBTRACTIONCHECK_H
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
namespace abseil {
/// Checks for cases where subtraction should be performed in the
/// `absl::Duration` domain.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-duration-subtraction.html
class DurationSubtractionCheck : public ClangTidyCheck {
public:
DurationSubtractionCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace abseil
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_DURATIONSUBTRACTIONCHECK_H

View File

@@ -1,131 +0,0 @@
//===--- FasterStrsplitDelimiterCheck.cpp - clang-tidy---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "FasterStrsplitDelimiterCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace abseil {
namespace {
AST_MATCHER(StringLiteral, lengthIsOne) { return Node.getLength() == 1; }
::internal::Matcher<Expr>
constructExprWithArg(llvm::StringRef ClassName,
const ::internal::Matcher<Expr> &Arg) {
auto ConstrExpr = cxxConstructExpr(hasType(recordDecl(hasName(ClassName))),
hasArgument(0, ignoringParenCasts(Arg)));
return anyOf(ConstrExpr, cxxBindTemporaryExpr(has(ConstrExpr)));
}
::internal::Matcher<Expr>
copyConstructExprWithArg(llvm::StringRef ClassName,
const ::internal::Matcher<Expr> &Arg) {
return constructExprWithArg(ClassName, constructExprWithArg(ClassName, Arg));
}
llvm::Optional<std::string> makeCharacterLiteral(const StringLiteral *Literal) {
std::string Result;
{
llvm::raw_string_ostream Stream(Result);
Literal->outputString(Stream);
}
// Special case: If the string contains a single quote, we just need to return
// a character of the single quote. This is a special case because we need to
// escape it in the character literal.
if (Result == R"("'")")
return std::string(R"('\'')");
assert(Result.size() == 3 || (Result.size() == 4 && Result.substr(0, 2) == "\"\\"));
// Now replace the " with '.
auto Pos = Result.find_first_of('"');
if (Pos == Result.npos)
return llvm::None;
Result[Pos] = '\'';
Pos = Result.find_last_of('"');
if (Pos == Result.npos)
return llvm::None;
Result[Pos] = '\'';
return Result;
}
} // anonymous namespace
void FasterStrsplitDelimiterCheck::registerMatchers(MatchFinder *Finder) {
if (!getLangOpts().CPlusPlus)
return;
// Binds to one character string literals.
const auto SingleChar =
expr(ignoringParenCasts(stringLiteral(lengthIsOne()).bind("Literal")));
// Binds to a string_view (either absl or std) that was passed by value and
// contructed from string literal.
auto StringViewArg =
copyConstructExprWithArg("::absl::string_view", SingleChar);
auto ByAnyCharArg =
expr(copyConstructExprWithArg("::absl::ByAnyChar", StringViewArg))
.bind("ByAnyChar");
// Find uses of absl::StrSplit(..., "x") and absl::StrSplit(...,
// absl::ByAnyChar("x")) to transform them into absl::StrSplit(..., 'x').
Finder->addMatcher(callExpr(callee(functionDecl(hasName("::absl::StrSplit"))),
hasArgument(1, anyOf(ByAnyCharArg, SingleChar)),
unless(isInTemplateInstantiation()))
.bind("StrSplit"),
this);
// Find uses of absl::MaxSplits("x", N) and
// absl::MaxSplits(absl::ByAnyChar("x"), N) to transform them into
// absl::MaxSplits('x', N).
Finder->addMatcher(
callExpr(
callee(functionDecl(hasName("::absl::MaxSplits"))),
hasArgument(0, anyOf(ByAnyCharArg, ignoringParenCasts(SingleChar))),
unless(isInTemplateInstantiation())),
this);
}
void FasterStrsplitDelimiterCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *Literal = Result.Nodes.getNodeAs<StringLiteral>("Literal");
if (Literal->getBeginLoc().isMacroID() || Literal->getEndLoc().isMacroID())
return;
llvm::Optional<std::string> Replacement = makeCharacterLiteral(Literal);
if (!Replacement)
return;
SourceRange Range = Literal->getSourceRange();
if (const auto *ByAnyChar = Result.Nodes.getNodeAs<Expr>("ByAnyChar"))
Range = ByAnyChar->getSourceRange();
diag(
Literal->getBeginLoc(),
"%select{absl::StrSplit()|absl::MaxSplits()}0 called with a string "
"literal "
"consisting of a single character; consider using the character overload")
<< (Result.Nodes.getNodeAs<CallExpr>("StrSplit") ? 0 : 1)
<< FixItHint::CreateReplacement(CharSourceRange::getTokenRange(Range),
*Replacement);
}
} // namespace abseil
} // namespace tidy
} // namespace clang

View File

@@ -1,36 +0,0 @@
//===--- FasterStrsplitDelimiterCheck.h - clang-tidy-------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_FASTERSTRSPLITDELIMITERCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_FASTERSTRSPLITDELIMITERCHECK_H
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
namespace abseil {
/// Finds instances of absl::StrSplit() or absl::MaxSplits() where the delimiter
/// is a single character string literal and replaces it with a character.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-faster-strsplit-delimiter.html
class FasterStrsplitDelimiterCheck : public ClangTidyCheck {
public:
FasterStrsplitDelimiterCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace abseil
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_FASTERSTRSPLITDELIMITERCHECK_H

View File

@@ -1,48 +0,0 @@
//===--- NoInternalDependenciesCheck.cpp - clang-tidy----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "NoInternalDependenciesCheck.h"
#include "AbseilMatcher.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace abseil {
void NoInternalDependenciesCheck::registerMatchers(MatchFinder *Finder) {
if (!getLangOpts().CPlusPlus)
return;
// TODO: refactor matcher to be configurable or just match on any internal
// access from outside the enclosing namespace.
Finder->addMatcher(
nestedNameSpecifierLoc(loc(specifiesNamespace(namespaceDecl(
matchesName("internal"),
hasParent(namespaceDecl(hasName("absl")))))),
unless(isInAbseilFile()))
.bind("InternalDep"),
this);
}
void NoInternalDependenciesCheck::check(const MatchFinder::MatchResult &Result) {
const auto *InternalDependency =
Result.Nodes.getNodeAs<NestedNameSpecifierLoc>("InternalDep");
diag(InternalDependency->getBeginLoc(),
"do not reference any 'internal' namespaces; those implementation "
"details are reserved to Abseil");
}
} // namespace abseil
} // namespace tidy
} // namespace clang

View File

@@ -1,36 +0,0 @@
//===--- NoInternalDependenciesCheck.h - clang-tidy----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_NOINTERNALDEPSCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_NOINTERNALDEPSCHECK_H
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
namespace abseil {
/// Finds instances where the user depends on internal details and warns them
/// against doing so.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-no-internal-dependencies.html
class NoInternalDependenciesCheck : public ClangTidyCheck {
public:
NoInternalDependenciesCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace abseil
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_NOINTERNALDEPSCHECK_H

View File

@@ -1,42 +0,0 @@
//===--- NoNamespaceCheck.cpp - clang-tidy---------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "NoNamespaceCheck.h"
#include "AbseilMatcher.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace abseil {
void NoNamespaceCheck::registerMatchers(MatchFinder *Finder) {
if (!getLangOpts().CPlusPlus)
return;
Finder->addMatcher(
namespaceDecl(hasName("::absl"), unless(isInAbseilFile()))
.bind("abslNamespace"),
this);
}
void NoNamespaceCheck::check(const MatchFinder::MatchResult &Result) {
const auto *abslNamespaceDecl =
Result.Nodes.getNodeAs<NamespaceDecl>("abslNamespace");
diag(abslNamespaceDecl->getLocation(),
"namespace 'absl' is reserved for implementation of the Abseil library "
"and should not be opened in user code");
}
} // namespace abseil
} // namespace tidy
} // namespace clang

View File

@@ -1,36 +0,0 @@
//===--- NoNamespaceCheck.h - clang-tidy-------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_NONAMESPACECHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_NONAMESPACECHECK_H
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
namespace abseil {
/// This check ensures users don't open namespace absl, as that violates
/// Abseil's compatibility guidelines.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-no-namespace.html
class NoNamespaceCheck : public ClangTidyCheck {
public:
NoNamespaceCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace abseil
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_NONAMESPACECHECK_H

View File

@@ -1,140 +0,0 @@
//===--- RedundantStrcatCallsCheck.cpp - clang-tidy------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "RedundantStrcatCallsCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace abseil {
// TODO: Features to add to the check:
// - Make it work if num_args > 26.
// - Remove empty literal string arguments.
// - Collapse consecutive literal string arguments into one (remove the ,).
// - Replace StrCat(a + b) -> StrCat(a, b) if a or b are strings.
// - Make it work in macros if the outer and inner StrCats are both in the
// argument.
void RedundantStrcatCallsCheck::registerMatchers(MatchFinder* Finder) {
if (!getLangOpts().CPlusPlus)
return;
const auto CallToStrcat =
callExpr(callee(functionDecl(hasName("::absl::StrCat"))));
const auto CallToStrappend =
callExpr(callee(functionDecl(hasName("::absl::StrAppend"))));
// Do not match StrCat() calls that are descendants of other StrCat calls.
// Those are handled on the ancestor call.
const auto CallToEither = callExpr(
callee(functionDecl(hasAnyName("::absl::StrCat", "::absl::StrAppend"))));
Finder->addMatcher(
callExpr(CallToStrcat, unless(hasAncestor(CallToEither))).bind("StrCat"),
this);
Finder->addMatcher(CallToStrappend.bind("StrAppend"), this);
}
namespace {
struct StrCatCheckResult {
int NumCalls = 0;
std::vector<FixItHint> Hints;
};
void RemoveCallLeaveArgs(const CallExpr* Call, StrCatCheckResult* CheckResult) {
// Remove 'Foo('
CheckResult->Hints.push_back(
FixItHint::CreateRemoval(CharSourceRange::getCharRange(
Call->getBeginLoc(), Call->getArg(0)->getBeginLoc())));
// Remove the ')'
CheckResult->Hints.push_back(
FixItHint::CreateRemoval(CharSourceRange::getCharRange(
Call->getRParenLoc(), Call->getEndLoc().getLocWithOffset(1))));
}
const clang::CallExpr* ProcessArgument(const Expr* Arg,
const MatchFinder::MatchResult& Result,
StrCatCheckResult* CheckResult) {
const auto IsAlphanum = hasDeclaration(cxxMethodDecl(hasName("AlphaNum")));
static const auto* const Strcat = new auto(hasName("::absl::StrCat"));
const auto IsStrcat = cxxBindTemporaryExpr(
has(callExpr(callee(functionDecl(*Strcat))).bind("StrCat")));
if (const auto* SubStrcatCall = selectFirst<const CallExpr>(
"StrCat",
match(stmt(anyOf(
cxxConstructExpr(IsAlphanum, hasArgument(0, IsStrcat)),
IsStrcat)),
*Arg->IgnoreParenImpCasts(), *Result.Context))) {
RemoveCallLeaveArgs(SubStrcatCall, CheckResult);
return SubStrcatCall;
}
return nullptr;
}
StrCatCheckResult ProcessCall(const CallExpr* RootCall, bool IsAppend,
const MatchFinder::MatchResult& Result) {
StrCatCheckResult CheckResult;
std::deque<const CallExpr*> CallsToProcess = {RootCall};
while (!CallsToProcess.empty()) {
++CheckResult.NumCalls;
const CallExpr* CallExpr = CallsToProcess.front();
CallsToProcess.pop_front();
int StartArg = CallExpr == RootCall && IsAppend;
for (const auto *Arg : CallExpr->arguments()) {
if (StartArg-- > 0)
continue;
if (const clang::CallExpr* Sub =
ProcessArgument(Arg, Result, &CheckResult)) {
CallsToProcess.push_back(Sub);
}
}
}
return CheckResult;
}
} // namespace
void RedundantStrcatCallsCheck::check(const MatchFinder::MatchResult& Result) {
bool IsAppend;
const CallExpr* RootCall;
if ((RootCall = Result.Nodes.getNodeAs<CallExpr>("StrCat")))
IsAppend = false;
else if ((RootCall = Result.Nodes.getNodeAs<CallExpr>("StrAppend")))
IsAppend = true;
else
return;
if (RootCall->getBeginLoc().isMacroID()) {
// Ignore calls within macros.
// In many cases the outer StrCat part of the macro and the inner StrCat is
// a macro argument. Removing the inner StrCat() converts one macro
// argument into many.
return;
}
const StrCatCheckResult CheckResult =
ProcessCall(RootCall, IsAppend, Result);
if (CheckResult.NumCalls == 1) {
// Just one call, so nothing to fix.
return;
}
diag(RootCall->getBeginLoc(),
"multiple calls to 'absl::StrCat' can be flattened into a single call")
<< CheckResult.Hints;
}
} // namespace abseil
} // namespace tidy
} // namespace clang

View File

@@ -1,39 +0,0 @@
//===--- RedundantStrcatCallsCheck.h - clang-tidy----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_REDUNDANTSTRCATCALLSCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_REDUNDANTSTRCATCALLSCHECK_H
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
namespace abseil {
/// Flags redundant calls to absl::StrCat when the result is being passed to
/// another call of absl::StrCat/absl::StrAppend. Also suggests a fix to
/// collapse the calls.
/// Example:
/// StrCat(1, StrCat(2, 3)) ==> StrCat(1, 2, 3)
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-redundant-strcat-calls.html
class RedundantStrcatCallsCheck : public ClangTidyCheck {
public:
RedundantStrcatCallsCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace abseil
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_REDUNDANTSTRCATCALLSCHECK_H

View File

@@ -1,102 +0,0 @@
//===--- StrCatAppendCheck.cpp - clang-tidy--------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "StrCatAppendCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace abseil {
namespace {
// Skips any combination of temporary materialization, temporary binding and
// implicit casting.
AST_MATCHER_P(Stmt, IgnoringTemporaries, ast_matchers::internal::Matcher<Stmt>,
InnerMatcher) {
const Stmt *E = &Node;
while (true) {
if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
E = MTE->getTemporary();
if (const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
E = BTE->getSubExpr();
if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E))
E = ICE->getSubExpr();
else
break;
}
return InnerMatcher.matches(*E, Finder, Builder);
}
} // namespace
// TODO: str += StrCat(...)
// str.append(StrCat(...))
void StrCatAppendCheck::registerMatchers(MatchFinder *Finder) {
if (!getLangOpts().CPlusPlus)
return;
const auto StrCat = functionDecl(hasName("::absl::StrCat"));
// The arguments of absl::StrCat are implicitly converted to AlphaNum. This
// matches to the arguments because of that behavior.
const auto AlphaNum = IgnoringTemporaries(cxxConstructExpr(
argumentCountIs(1), hasType(cxxRecordDecl(hasName("::absl::AlphaNum"))),
hasArgument(0, ignoringImpCasts(declRefExpr(to(equalsBoundNode("LHS")),
expr().bind("Arg0"))))));
const auto HasAnotherReferenceToLhs =
callExpr(hasAnyArgument(expr(hasDescendant(declRefExpr(
to(equalsBoundNode("LHS")), unless(equalsBoundNode("Arg0")))))));
// Now look for calls to operator= with an object on the LHS and a call to
// StrCat on the RHS. The first argument of the StrCat call should be the same
// as the LHS. Ignore calls from template instantiations.
Finder->addMatcher(
cxxOperatorCallExpr(
unless(isInTemplateInstantiation()), hasOverloadedOperatorName("="),
hasArgument(0, declRefExpr(to(decl().bind("LHS")))),
hasArgument(1, IgnoringTemporaries(
callExpr(callee(StrCat), hasArgument(0, AlphaNum),
unless(HasAnotherReferenceToLhs))
.bind("Call"))))
.bind("Op"),
this);
}
void StrCatAppendCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Op = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("Op");
const auto *Call = Result.Nodes.getNodeAs<CallExpr>("Call");
assert(Op != nullptr && Call != nullptr && "Matcher does not work as expected");
// Handles the case 'x = absl::StrCat(x)', which has no effect.
if (Call->getNumArgs() == 1) {
diag(Op->getBeginLoc(), "call to 'absl::StrCat' has no effect");
return;
}
// Emit a warning and emit fixits to go from
// x = absl::StrCat(x, ...)
// to
// absl::StrAppend(&x, ...)
diag(Op->getBeginLoc(),
"call 'absl::StrAppend' instead of 'absl::StrCat' when appending to a "
"string to avoid a performance penalty")
<< FixItHint::CreateReplacement(
CharSourceRange::getTokenRange(Op->getBeginLoc(),
Call->getCallee()->getEndLoc()),
"absl::StrAppend")
<< FixItHint::CreateInsertion(Call->getArg(0)->getBeginLoc(), "&");
}
} // namespace abseil
} // namespace tidy
} // namespace clang

View File

@@ -1,36 +0,0 @@
//===--- StrCatAppendCheck.h - clang-tidy------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_STRCATAPPENDCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_STRCATAPPENDCHECK_H
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
namespace abseil {
/// Flags uses of absl::StrCat to append to a string. Suggests absl::StrAppend
/// should be used instead.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-str-cat-append.html
class StrCatAppendCheck : public ClangTidyCheck {
public:
StrCatAppendCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace abseil
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_STRCATAPPENDCHECK_H

View File

@@ -71,7 +71,7 @@ void StringFindStartswithCheck::check(const MatchFinder::MatchResult &Result) {
->getImplicitObjectArgument();
assert(Haystack != nullptr);
if (ComparisonExpr->getBeginLoc().isMacroID())
if (ComparisonExpr->getLocStart().isMacroID())
return;
// Get the source code blocks (as characters) for both the string object
@@ -94,7 +94,7 @@ void StringFindStartswithCheck::check(const MatchFinder::MatchResult &Result) {
// Create the warning message and a FixIt hint replacing the original expr.
auto Diagnostic =
diag(ComparisonExpr->getBeginLoc(),
diag(ComparisonExpr->getLocStart(),
(StringRef("use ") + StartswithStr + " instead of find() " +
ComparisonExpr->getOpcodeStr() + " 0")
.str());
@@ -107,7 +107,7 @@ void StringFindStartswithCheck::check(const MatchFinder::MatchResult &Result) {
// Create a preprocessor #include FixIt hint (CreateIncludeInsertion checks
// whether this already exists).
auto IncludeHint = IncludeInserter->CreateIncludeInsertion(
Source.getFileID(ComparisonExpr->getBeginLoc()), AbseilStringsMatchHeader,
Source.getFileID(ComparisonExpr->getLocStart()), AbseilStringsMatchHeader,
false);
if (IncludeHint) {
Diagnostic << *IncludeHint;

View File

@@ -1,156 +0,0 @@
//===--- UpgradeDurationConversionsCheck.cpp - clang-tidy -----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "UpgradeDurationConversionsCheck.h"
#include "DurationRewriter.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace abseil {
void UpgradeDurationConversionsCheck::registerMatchers(MatchFinder *Finder) {
if (!getLangOpts().CPlusPlus)
return;
// For the arithmetic calls, we match only the uses of the templated operators
// where the template parameter is not a built-in type. This means the
// instantiation makes use of an available user defined conversion to
// `int64_t`.
//
// The implementation of these templates will be updated to fail SFINAE for
// non-integral types. We match them to suggest an explicit cast.
// Match expressions like `a *= b` and `a /= b` where `a` has type
// `absl::Duration` and `b` is not of a built-in type.
Finder->addMatcher(
cxxOperatorCallExpr(
argumentCountIs(2),
hasArgument(
0, expr(hasType(cxxRecordDecl(hasName("::absl::Duration"))))),
hasArgument(1, expr().bind("arg")),
callee(functionDecl(
hasParent(functionTemplateDecl()),
unless(hasTemplateArgument(0, refersToType(builtinType()))),
hasAnyName("operator*=", "operator/=")))),
this);
// Match expressions like `a.operator*=(b)` and `a.operator/=(b)` where `a`
// has type `absl::Duration` and `b` is not of a built-in type.
Finder->addMatcher(
cxxMemberCallExpr(
callee(cxxMethodDecl(
ofClass(cxxRecordDecl(hasName("::absl::Duration"))),
hasParent(functionTemplateDecl()),
unless(hasTemplateArgument(0, refersToType(builtinType()))),
hasAnyName("operator*=", "operator/="))),
argumentCountIs(1), hasArgument(0, expr().bind("arg"))),
this);
// Match expressions like `a * b`, `a / b`, `operator*(a, b)`, and
// `operator/(a, b)` where `a` has type `absl::Duration` and `b` is not of a
// built-in type.
Finder->addMatcher(
callExpr(callee(functionDecl(
hasParent(functionTemplateDecl()),
unless(hasTemplateArgument(0, refersToType(builtinType()))),
hasAnyName("::absl::operator*", "::absl::operator/"))),
argumentCountIs(2),
hasArgument(0, expr(hasType(
cxxRecordDecl(hasName("::absl::Duration"))))),
hasArgument(1, expr().bind("arg"))),
this);
// Match expressions like `a * b` and `operator*(a, b)` where `a` is not of a
// built-in type and `b` has type `absl::Duration`.
Finder->addMatcher(
callExpr(callee(functionDecl(
hasParent(functionTemplateDecl()),
unless(hasTemplateArgument(0, refersToType(builtinType()))),
hasName("::absl::operator*"))),
argumentCountIs(2), hasArgument(0, expr().bind("arg")),
hasArgument(1, expr(hasType(cxxRecordDecl(
hasName("::absl::Duration")))))),
this);
// For the factory functions, we match only the non-templated overloads that
// take an `int64_t` parameter. Within these calls, we care about implicit
// casts through a user defined conversion to `int64_t`.
//
// The factory functions will be updated to be templated and SFINAE on whether
// the template parameter is an integral type. This complements the already
// existing templated overloads that only accept floating point types.
// Match calls like:
// `absl::Nanoseconds(x)`
// `absl::Microseconds(x)`
// `absl::Milliseconds(x)`
// `absl::Seconds(x)`
// `absl::Minutes(x)`
// `absl::Hours(x)`
// where `x` is not of a built-in type.
Finder->addMatcher(
implicitCastExpr(
anyOf(hasCastKind(CK_UserDefinedConversion),
has(implicitCastExpr(hasCastKind(CK_UserDefinedConversion)))),
hasParent(callExpr(
callee(functionDecl(DurationFactoryFunction(),
unless(hasParent(functionTemplateDecl())))),
hasArgument(0, expr().bind("arg"))))),
this);
}
void UpgradeDurationConversionsCheck::check(
const MatchFinder::MatchResult &Result) {
const llvm::StringRef Message =
"implicit conversion to 'int64_t' is deprecated in this context; use an "
"explicit cast instead";
const auto *ArgExpr = Result.Nodes.getNodeAs<Expr>("arg");
SourceLocation Loc = ArgExpr->getBeginLoc();
if (!match(isInTemplateInstantiation(), *ArgExpr, *Result.Context).empty()) {
if (MatchedTemplateLocations.count(Loc.getRawEncoding()) == 0) {
// For each location matched in a template instantiation, we check if the
// location can also be found in `MatchedTemplateLocations`. If it is not
// found, that means the expression did not create a match without the
// instantiation and depends on template parameters. A manual fix is
// probably required so we provide only a warning.
diag(Loc, Message);
}
return;
}
// We gather source locations from template matches not in template
// instantiations for future matches.
internal::Matcher<Stmt> IsInsideTemplate =
hasAncestor(decl(anyOf(classTemplateDecl(), functionTemplateDecl())));
if (!match(IsInsideTemplate, *ArgExpr, *Result.Context).empty())
MatchedTemplateLocations.insert(Loc.getRawEncoding());
DiagnosticBuilder Diag = diag(Loc, Message);
CharSourceRange SourceRange = Lexer::makeFileCharRange(
CharSourceRange::getTokenRange(ArgExpr->getSourceRange()),
*Result.SourceManager, Result.Context->getLangOpts());
if (SourceRange.isInvalid())
// An invalid source range likely means we are inside a macro body. A manual
// fix is likely needed so we do not create a fix-it hint.
return;
Diag << FixItHint::CreateInsertion(SourceRange.getBegin(),
"static_cast<int64_t>(")
<< FixItHint::CreateInsertion(SourceRange.getEnd(), ")");
}
} // namespace abseil
} // namespace tidy
} // namespace clang

View File

@@ -1,40 +0,0 @@
//===--- UpgradeDurationConversionsCheck.h - clang-tidy ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_UPGRADEDURATIONCONVERSIONSCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_UPGRADEDURATIONCONVERSIONSCHECK_H
#include "../ClangTidy.h"
#include <unordered_set>
namespace clang {
namespace tidy {
namespace abseil {
/// Finds deprecated uses of `absl::Duration` arithmetic operators and factories.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/abseil-upgrade-duration-conversions.html
class UpgradeDurationConversionsCheck : public ClangTidyCheck {
public:
UpgradeDurationConversionsCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
private:
std::unordered_set<unsigned> MatchedTemplateLocations;
};
} // namespace abseil
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_UPGRADEDURATIONCONVERSIONSCHECK_H

View File

@@ -56,8 +56,8 @@ def write_header(module_path, module, check_name, check_name_camel):
+ check_name_camel.upper() + '_H')
f.write('//===--- ')
f.write(os.path.basename(filename))
f.write(' - clang-tidy ')
f.write('-' * max(0, 42 - len(os.path.basename(filename))))
f.write(' - clang-tidy')
f.write('-' * max(0, 43 - len(os.path.basename(filename))))
f.write('*- C++ -*-===//')
f.write("""
//
@@ -107,8 +107,8 @@ def write_implementation(module_path, module, check_name_camel):
with open(filename, 'w') as f:
f.write('//===--- ')
f.write(os.path.basename(filename))
f.write(' - clang-tidy ')
f.write('-' * max(0, 51 - len(os.path.basename(filename))))
f.write(' - clang-tidy')
f.write('-' * max(0, 52 - len(os.path.basename(filename))))
f.write('-===//')
f.write("""
//
@@ -200,47 +200,23 @@ def add_release_notes(module_path, module, check_name):
with open(filename, 'r') as f:
lines = f.readlines()
lineMatcher = re.compile('Improvements to clang-tidy')
nextSectionMatcher = re.compile('Improvements to include-fixer')
checkerMatcher = re.compile('- New :doc:`(.*)')
print('Updating %s...' % filename)
with open(filename, 'w') as f:
note_added = False
header_found = False
next_header_found = False
add_note_here = False
for line in lines:
if not note_added:
match = lineMatcher.match(line)
match_next = nextSectionMatcher.match(line)
match_checker = checkerMatcher.match(line)
if match_checker:
last_checker = match_checker.group(1)
if last_checker > check_name_dashes:
add_note_here = True
if match_next:
next_header_found = True
add_note_here = True
match = re.search('Improvements to clang-tidy', line)
if match:
header_found = True
f.write(line)
continue
if line.startswith('----'):
f.write(line)
continue
if header_found and add_note_here:
elif header_found:
if not line.startswith('----'):
f.write("""- New :doc:`%s
f.write("""
- New :doc:`%s
<clang-tidy/checks/%s>` check.
FIXME: add release notes.
""" % (check_name_dashes, check_name_dashes))
note_added = True

View File

@@ -37,16 +37,16 @@ public:
CheckFactories.registerCheck<CloexecAccept4Check>("android-cloexec-accept4");
CheckFactories.registerCheck<CloexecAcceptCheck>("android-cloexec-accept");
CheckFactories.registerCheck<CloexecCreatCheck>("android-cloexec-creat");
CheckFactories.registerCheck<CloexecDupCheck>("android-cloexec-dup");
CheckFactories.registerCheck<CloexecEpollCreate1Check>(
"android-cloexec-epoll-create1");
CheckFactories.registerCheck<CloexecEpollCreateCheck>(
"android-cloexec-epoll-create");
CheckFactories.registerCheck<CloexecDupCheck>("android-cloexec-dup");
CheckFactories.registerCheck<CloexecFopenCheck>("android-cloexec-fopen");
CheckFactories.registerCheck<CloexecInotifyInit1Check>(
"android-cloexec-inotify-init1");
CheckFactories.registerCheck<CloexecInotifyInitCheck>(
"android-cloexec-inotify-init");
CheckFactories.registerCheck<CloexecInotifyInit1Check>(
"android-cloexec-inotify-init1");
CheckFactories.registerCheck<CloexecMemfdCreateCheck>(
"android-cloexec-memfd-create");
CheckFactories.registerCheck<CloexecOpenCheck>("android-cloexec-open");

View File

@@ -6,9 +6,9 @@ add_clang_library(clangTidyAndroidModule
CloexecAcceptCheck.cpp
CloexecCheck.cpp
CloexecCreatCheck.cpp
CloexecDupCheck.cpp
CloexecEpollCreate1Check.cpp
CloexecEpollCreateCheck.cpp
CloexecDupCheck.cpp
CloexecFopenCheck.cpp
CloexecInotifyInit1Check.cpp
CloexecInotifyInitCheck.cpp

View File

@@ -25,7 +25,7 @@ namespace {
// end of the string. Else, add <Mode>.
std::string buildFixMsgForStringFlag(const Expr *Arg, const SourceManager &SM,
const LangOptions &LangOpts, char Mode) {
if (Arg->getBeginLoc().isMacroID())
if (Arg->getLocStart().isMacroID())
return (Lexer::getSourceText(
CharSourceRange::getTokenRange(Arg->getSourceRange()), SM,
LangOpts) +
@@ -64,7 +64,7 @@ void CloexecCheck::insertMacroFlag(const MatchFinder::MatchResult &Result,
return;
SourceLocation EndLoc =
Lexer::getLocForEndOfToken(SM.getFileLoc(FlagArg->getEndLoc()), 0, SM,
Lexer::getLocForEndOfToken(SM.getFileLoc(FlagArg->getLocEnd()), 0, SM,
Result.Context->getLangOpts());
diag(EndLoc, "%0 should use %1 where possible")
@@ -75,7 +75,7 @@ void CloexecCheck::insertMacroFlag(const MatchFinder::MatchResult &Result,
void CloexecCheck::replaceFunc(const MatchFinder::MatchResult &Result,
StringRef WarningMsg, StringRef FixMsg) {
const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(FuncBindingStr);
diag(MatchedCall->getBeginLoc(), WarningMsg)
diag(MatchedCall->getLocStart(), WarningMsg)
<< FixItHint::CreateReplacement(MatchedCall->getSourceRange(), FixMsg);
}
@@ -94,7 +94,7 @@ void CloexecCheck::insertStringFlag(
const std::string &ReplacementText = buildFixMsgForStringFlag(
ModeArg, *Result.SourceManager, Result.Context->getLangOpts(), Mode);
diag(ModeArg->getBeginLoc(), "use %0 mode '%1' to set O_CLOEXEC")
diag(ModeArg->getLocStart(), "use %0 mode '%1' to set O_CLOEXEC")
<< FD << std::string(1, Mode)
<< FixItHint::CreateReplacement(ModeArg->getSourceRange(),
ReplacementText);

View File

@@ -21,15 +21,15 @@ namespace android {
namespace {
AST_MATCHER(BinaryOperator, isRHSATempFailureRetryArg) {
if (!Node.getBeginLoc().isMacroID())
if (!Node.getLocStart().isMacroID())
return false;
const SourceManager &SM = Finder->getASTContext().getSourceManager();
if (!SM.isMacroArgExpansion(Node.getRHS()->IgnoreParenCasts()->getBeginLoc()))
if (!SM.isMacroArgExpansion(Node.getRHS()->IgnoreParenCasts()->getLocStart()))
return false;
const LangOptions &Opts = Finder->getASTContext().getLangOpts();
SourceLocation LocStart = Node.getBeginLoc();
SourceLocation LocStart = Node.getLocStart();
while (LocStart.isMacroID()) {
SourceLocation Invocation = SM.getImmediateMacroCallerLoc(LocStart);
Token Tok;

View File

@@ -56,7 +56,7 @@ void UseToStringCheck::check(const MatchFinder::MatchResult &Result) {
else
return;
auto Loc = Call->getBeginLoc();
auto Loc = Call->getLocStart();
auto Diag =
diag(Loc, "use std::to_%0 instead of boost::lexical_cast<std::%0>")
<< StringType;
@@ -65,8 +65,8 @@ void UseToStringCheck::check(const MatchFinder::MatchResult &Result) {
return;
Diag << FixItHint::CreateReplacement(
CharSourceRange::getCharRange(Call->getBeginLoc(),
Call->getArg(0)->getBeginLoc()),
CharSourceRange::getCharRange(Call->getLocStart(),
Call->getArg(0)->getLocStart()),
(llvm::Twine("std::to_") + StringType + "(").str());
}

View File

@@ -91,9 +91,8 @@ static std::vector<std::pair<SourceLocation, StringRef>>
getCommentsBeforeLoc(ASTContext *Ctx, SourceLocation Loc) {
std::vector<std::pair<SourceLocation, StringRef>> Comments;
while (Loc.isValid()) {
clang::Token Tok = utils::lexer::getPreviousToken(
Loc, Ctx->getSourceManager(), Ctx->getLangOpts(),
/*SkipComments=*/false);
clang::Token Tok =
utils::lexer::getPreviousToken(*Ctx, Loc, /*SkipComments=*/false);
if (Tok.isNot(tok::comment))
break;
Loc = Tok.getLocation();
@@ -243,8 +242,8 @@ void ArgumentCommentCheck::checkCallArgs(ASTContext *Ctx,
}
CharSourceRange BeforeArgument =
makeFileCharRange(ArgBeginLoc, Args[I]->getBeginLoc());
ArgBeginLoc = Args[I]->getEndLoc();
makeFileCharRange(ArgBeginLoc, Args[I]->getLocStart());
ArgBeginLoc = Args[I]->getLocEnd();
std::vector<std::pair<SourceLocation, StringRef>> Comments;
if (BeforeArgument.isValid()) {
@@ -252,7 +251,7 @@ void ArgumentCommentCheck::checkCallArgs(ASTContext *Ctx,
} else {
// Fall back to parsing back from the start of the argument.
CharSourceRange ArgsRange = makeFileCharRange(
Args[I]->getBeginLoc(), Args[NumArgs - 1]->getEndLoc());
Args[I]->getLocStart(), Args[NumArgs - 1]->getLocEnd());
Comments = getCommentsBeforeLoc(Ctx, ArgsRange.getBegin());
}
@@ -288,7 +287,7 @@ void ArgumentCommentCheck::check(const MatchFinder::MatchResult &Result) {
if (!Callee)
return;
checkCallArgs(Result.Context, Callee, Call->getCallee()->getEndLoc(),
checkCallArgs(Result.Context, Callee, Call->getCallee()->getLocEnd(),
llvm::makeArrayRef(Call->getArgs(), Call->getNumArgs()));
} else {
const auto *Construct = cast<CXXConstructExpr>(E);

View File

@@ -102,7 +102,7 @@ void AssertSideEffectCheck::registerMatchers(MatchFinder *Finder) {
void AssertSideEffectCheck::check(const MatchFinder::MatchResult &Result) {
const SourceManager &SM = *Result.SourceManager;
const LangOptions LangOpts = getLangOpts();
SourceLocation Loc = Result.Nodes.getNodeAs<Stmt>("condStmt")->getBeginLoc();
SourceLocation Loc = Result.Nodes.getNodeAs<Stmt>("condStmt")->getLocStart();
StringRef AssertMacroName;
while (Loc.isValid() && Loc.isMacroID()) {

View File

@@ -20,11 +20,11 @@ void BoolPointerImplicitConversionCheck::registerMatchers(MatchFinder *Finder) {
// condition. Filter negations.
Finder->addMatcher(
ifStmt(hasCondition(findAll(implicitCastExpr(
unless(hasParent(unaryOperator(hasOperatorName("!")))),
hasSourceExpression(
expr(hasType(pointerType(pointee(booleanType()))),
ignoringParenImpCasts(declRefExpr().bind("expr")))),
hasCastKind(CK_PointerToBoolean)))),
allOf(unless(hasParent(unaryOperator(hasOperatorName("!")))),
hasSourceExpression(expr(
hasType(pointerType(pointee(booleanType()))),
ignoringParenImpCasts(declRefExpr().bind("expr")))),
hasCastKind(CK_PointerToBoolean))))),
unless(isInTemplateInstantiation()))
.bind("if"),
this);
@@ -36,7 +36,7 @@ void BoolPointerImplicitConversionCheck::check(
auto *Var = Result.Nodes.getNodeAs<DeclRefExpr>("expr");
// Ignore macros.
if (Var->getBeginLoc().isMacroID())
if (Var->getLocStart().isMacroID())
return;
// Only allow variable accesses for now, no function calls or member exprs.
@@ -63,9 +63,9 @@ void BoolPointerImplicitConversionCheck::check(
.empty())
return;
diag(Var->getBeginLoc(), "dubious check of 'bool *' against 'nullptr', did "
diag(Var->getLocStart(), "dubious check of 'bool *' against 'nullptr', did "
"you mean to dereference it?")
<< FixItHint::CreateInsertion(Var->getBeginLoc(), "*");
<< FixItHint::CreateInsertion(Var->getLocStart(), "*");
}
} // namespace bugprone

View File

@@ -44,7 +44,6 @@
#include "SwappedArgumentsCheck.h"
#include "TerminatingContinueCheck.h"
#include "ThrowKeywordMissingCheck.h"
#include "TooSmallLoopVariableCheck.h"
#include "UndefinedMemoryManipulationCheck.h"
#include "UndelegatedConstructorCheck.h"
#include "UnusedRaiiCheck.h"
@@ -97,8 +96,6 @@ public:
"bugprone-move-forwarding-reference");
CheckFactories.registerCheck<MultipleStatementMacroCheck>(
"bugprone-multiple-statement-macro");
CheckFactories.registerCheck<TooSmallLoopVariableCheck>(
"bugprone-too-small-loop-variable");
CheckFactories.registerCheck<cppcoreguidelines::NarrowingConversionsCheck>(
"bugprone-narrowing-conversions");
CheckFactories.registerCheck<ParentVirtualCallCheck>(

View File

@@ -35,7 +35,6 @@ add_clang_library(clangTidyBugproneModule
SwappedArgumentsCheck.cpp
TerminatingContinueCheck.cpp
ThrowKeywordMissingCheck.cpp
TooSmallLoopVariableCheck.cpp
UndefinedMemoryManipulationCheck.cpp
UndelegatedConstructorCheck.cpp
UnusedRaiiCheck.cpp

View File

@@ -81,7 +81,7 @@ void CopyConstructorInitCheck::check(const MatchFinder::MatchResult &Result) {
if (CtorInitIsWritten) {
if (!ParamName.empty())
SafeFixIts.push_back(
FixItHint::CreateInsertion(CExpr->getEndLoc(), ParamName));
FixItHint::CreateInsertion(CExpr->getLocEnd(), ParamName));
} else {
if (Init->getSourceLocation().isMacroID() ||
Ctor->getLocation().isMacroID() || ShouldNotDoFixit)
@@ -104,7 +104,7 @@ void CopyConstructorInitCheck::check(const MatchFinder::MatchResult &Result) {
SourceLocation FixItLoc;
// There is no initialization list in this constructor.
if (!HasWrittenInitializer) {
FixItLoc = Ctor->getBody()->getBeginLoc();
FixItLoc = Ctor->getBody()->getLocStart();
FixItMsg = " : " + FixItMsg;
} else {
// We apply the missing ctors at the beginning of the initialization list.

View File

@@ -178,7 +178,7 @@ void DanglingHandleCheck::registerMatchers(MatchFinder *Finder) {
void DanglingHandleCheck::check(const MatchFinder::MatchResult &Result) {
auto *Handle = Result.Nodes.getNodeAs<CXXRecordDecl>("handle");
diag(Result.Nodes.getNodeAs<Stmt>("bad_stmt")->getBeginLoc(),
diag(Result.Nodes.getNodeAs<Stmt>("bad_stmt")->getLocStart(),
"%0 outlives its value")
<< Handle->getQualifiedNameAsString();
}

View File

@@ -186,16 +186,13 @@ void ExceptionEscapeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
}
void ExceptionEscapeCheck::registerMatchers(MatchFinder *Finder) {
if (!getLangOpts().CPlusPlus || !getLangOpts().CXXExceptions)
return;
Finder->addMatcher(
functionDecl(anyOf(isNoThrow(), cxxDestructorDecl(),
cxxConstructorDecl(isMoveConstructor()),
cxxMethodDecl(isMoveAssignmentOperator()),
hasName("main"), hasName("swap"),
isEnabled(FunctionsThatShouldNotThrow)),
throws(unless(isIgnored(IgnoredExceptions))))
functionDecl(allOf(anyOf(isNoThrow(), cxxDestructorDecl(),
cxxConstructorDecl(isMoveConstructor()),
cxxMethodDecl(isMoveAssignmentOperator()),
hasName("main"), hasName("swap"),
isEnabled(FunctionsThatShouldNotThrow)),
throws(unless(isIgnored(IgnoredExceptions)))))
.bind("thrower"),
this);
}

View File

@@ -57,7 +57,7 @@ void InaccurateEraseCheck::check(const MatchFinder::MatchResult &Result) {
Result.Nodes.getNodeAs<CXXMemberCallExpr>("erase");
const auto *EndExpr =
Result.Nodes.getNodeAs<CXXMemberCallExpr>("end");
const SourceLocation Loc = MemberCall->getBeginLoc();
const SourceLocation Loc = MemberCall->getLocStart();
FixItHint Hint;
@@ -67,7 +67,7 @@ void InaccurateEraseCheck::check(const MatchFinder::MatchResult &Result) {
CharSourceRange::getTokenRange(EndExpr->getSourceRange()),
*Result.SourceManager, getLangOpts());
const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
AlgCall->getEndLoc(), 0, *Result.SourceManager, getLangOpts());
AlgCall->getLocEnd(), 0, *Result.SourceManager, getLangOpts());
Hint = FixItHint::CreateInsertion(EndLoc, ", " + ReplacementText);
}

View File

@@ -61,7 +61,7 @@ void IncorrectRoundingsCheck::registerMatchers(MatchFinder *MatchFinder) {
void IncorrectRoundingsCheck::check(const MatchFinder::MatchResult &Result) {
const auto *CastExpr = Result.Nodes.getNodeAs<ImplicitCastExpr>("CastExpr");
diag(CastExpr->getBeginLoc(),
diag(CastExpr->getLocStart(),
"casting (double + 0.5) to integer leads to incorrect rounding; "
"consider using lround (#include <cmath>) instead");
}

View File

@@ -48,7 +48,7 @@ void IntegerDivisionCheck::registerMatchers(MatchFinder *Finder) {
void IntegerDivisionCheck::check(const MatchFinder::MatchResult &Result) {
const auto *IntDiv = Result.Nodes.getNodeAs<BinaryOperator>("IntDiv");
diag(IntDiv->getBeginLoc(), "result of integer division used in a floating "
diag(IntDiv->getLocStart(), "result of integer division used in a floating "
"point context; possible loss of precision");
}

View File

@@ -73,8 +73,8 @@ void LambdaFunctionNameCheck::registerPPCallbacks(CompilerInstance &Compiler) {
void LambdaFunctionNameCheck::check(const MatchFinder::MatchResult &Result) {
const auto *E = Result.Nodes.getNodeAs<PredefinedExpr>("E");
if (E->getIdentKind() != PredefinedExpr::Func &&
E->getIdentKind() != PredefinedExpr::Function) {
if (E->getIdentType() != PredefinedExpr::Func &&
E->getIdentType() != PredefinedExpr::Function) {
// We don't care about other PredefinedExprs.
return;
}
@@ -91,7 +91,7 @@ void LambdaFunctionNameCheck::check(const MatchFinder::MatchResult &Result) {
"inside a lambda, '%0' expands to the name of the function call "
"operator; consider capturing the name of the enclosing function "
"explicitly")
<< PredefinedExpr::getIdentKindName(E->getIdentKind());
<< PredefinedExpr::getIdentTypeName(E->getIdentType());
}
} // namespace bugprone

View File

@@ -29,17 +29,17 @@ void MisplacedOperatorInStrlenInAllocCheck::registerMatchers(
const auto BadUse =
callExpr(callee(StrLenFunc),
hasAnyArgument(ignoringImpCasts(
binaryOperator(
hasOperatorName("+"),
hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))
binaryOperator(allOf(hasOperatorName("+"),
hasRHS(ignoringParenImpCasts(
integerLiteral(equals(1))))))
.bind("BinOp"))))
.bind("StrLen");
const auto BadArg = anyOf(
allOf(unless(binaryOperator(
allOf(hasDescendant(BadUse),
unless(binaryOperator(allOf(
hasOperatorName("+"), hasLHS(BadUse),
hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))),
hasDescendant(BadUse)),
hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))))),
BadUse);
const auto Alloc0Func =
@@ -102,10 +102,9 @@ void MisplacedOperatorInStrlenInAllocCheck::check(
StrLen->getSourceRange(),
(StrLenBegin + LHSText + StrLenEnd + " + " + RHSText).str());
diag(Alloc->getBeginLoc(),
diag(Alloc->getLocStart(),
"addition operator is applied to the argument of %0 instead of its "
"result")
<< StrLen->getDirectCallee()->getName() << Hint;
"result") << StrLen->getDirectCallee()->getName() << Hint;
}
} // namespace bugprone

View File

@@ -65,16 +65,16 @@ static unsigned getMaxCalculationWidth(const ASTContext &Context,
if (Bop->getOpcode() == BO_Add)
return std::max(LHSWidth, RHSWidth) + 1;
if (Bop->getOpcode() == BO_Rem) {
Expr::EvalResult Result;
if (Bop->getRHS()->EvaluateAsInt(Result, Context))
return Result.Val.getInt().getActiveBits();
llvm::APSInt Val;
if (Bop->getRHS()->EvaluateAsInt(Val, Context))
return Val.getActiveBits();
} else if (Bop->getOpcode() == BO_Shl) {
Expr::EvalResult Result;
if (Bop->getRHS()->EvaluateAsInt(Result, Context)) {
llvm::APSInt Bits;
if (Bop->getRHS()->EvaluateAsInt(Bits, Context)) {
// We don't handle negative values and large values well. It is assumed
// that compiler warnings are written for such values so the user will
// fix that.
return LHSWidth + Result.Val.getInt().getExtValue();
return LHSWidth + Bits.getExtValue();
}
// Unknown bitcount, assume there is truncation.
@@ -185,11 +185,11 @@ void MisplacedWideningCastCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Cast = Result.Nodes.getNodeAs<CastExpr>("Cast");
if (!CheckImplicitCasts && isa<ImplicitCastExpr>(Cast))
return;
if (Cast->getBeginLoc().isMacroID())
if (Cast->getLocStart().isMacroID())
return;
const auto *Calc = Result.Nodes.getNodeAs<Expr>("Calc");
if (Calc->getBeginLoc().isMacroID())
if (Calc->getLocStart().isMacroID())
return;
if (Cast->isTypeDependent() || Cast->isValueDependent() ||
@@ -213,9 +213,8 @@ void MisplacedWideningCastCheck::check(const MatchFinder::MatchResult &Result) {
dyn_cast<BuiltinType>(CastType->getUnqualifiedDesugaredType());
const auto *CalcBuiltinType =
dyn_cast<BuiltinType>(CalcType->getUnqualifiedDesugaredType());
if (!CastBuiltinType || !CalcBuiltinType)
return;
if (!isFirstWider(CastBuiltinType->getKind(), CalcBuiltinType->getKind()))
if (CastBuiltinType && CalcBuiltinType &&
!isFirstWider(CastBuiltinType->getKind(), CalcBuiltinType->getKind()))
return;
}
@@ -224,7 +223,7 @@ void MisplacedWideningCastCheck::check(const MatchFinder::MatchResult &Result) {
if (Context.getIntWidth(CalcType) >= getMaxCalculationWidth(Context, Calc))
return;
diag(Cast->getBeginLoc(), "either cast from %0 to %1 is ineffective, or "
diag(Cast->getLocStart(), "either cast from %0 to %1 is ineffective, or "
"there is loss of precision before the conversion")
<< CalcType << CastType;
}

View File

@@ -29,7 +29,7 @@ static void replaceMoveWithForward(const UnresolvedLookupExpr *Callee,
CharSourceRange CallRange =
Lexer::makeFileCharRange(CharSourceRange::getTokenRange(
Callee->getBeginLoc(), Callee->getEndLoc()),
Callee->getLocStart(), Callee->getLocEnd()),
SM, LangOpts);
if (CallRange.isValid()) {

View File

@@ -19,7 +19,7 @@ namespace bugprone {
namespace {
AST_MATCHER(Expr, isInMacro) { return Node.getBeginLoc().isMacroID(); }
AST_MATCHER(Expr, isInMacro) { return Node.getLocStart().isMacroID(); }
/// \brief Find the next statement after `S`.
const Stmt *nextStmt(const MatchFinder::MatchResult &Result, const Stmt *S) {
@@ -73,13 +73,13 @@ void MultipleStatementMacroCheck::check(
if (!Next)
return;
SourceLocation OuterLoc = Outer->getBeginLoc();
SourceLocation OuterLoc = Outer->getLocStart();
if (Result.Nodes.getNodeAs<Stmt>("else"))
OuterLoc = cast<IfStmt>(Outer)->getElseLoc();
auto InnerRanges = getExpansionRanges(Inner->getBeginLoc(), Result);
auto InnerRanges = getExpansionRanges(Inner->getLocStart(), Result);
auto OuterRanges = getExpansionRanges(OuterLoc, Result);
auto NextRanges = getExpansionRanges(Next->getBeginLoc(), Result);
auto NextRanges = getExpansionRanges(Next->getLocStart(), Result);
// Remove all the common ranges, starting from the top (the last ones in the
// list).

View File

@@ -50,7 +50,9 @@ static BasesVector getParentsByGrandParent(const CXXRecordDecl &GrandParent,
// TypePtr is the nearest base class to ThisClass between ThisClass and
// GrandParent, where MemberDecl is overridden. TypePtr is the class the
// check proposes to fix to.
const Type *TypePtr = ActualMemberDecl->getThisType().getTypePtr();
const Type *TypePtr =
ActualMemberDecl->getThisType(ActualMemberDecl->getASTContext())
.getTypePtr();
const CXXRecordDecl *RecordDeclType = TypePtr->getPointeeCXXRecordDecl();
assert(RecordDeclType && "TypePtr is not a pointer to CXXRecordDecl!");
if (RecordDeclType->getCanonicalDecl()->isDerivedFrom(&GrandParent))

Some files were not shown because too many files have changed in this diff Show More