Use namespaces::

This commit is contained in:
Clément Fournier
2018-11-14 14:13:59 +01:00
parent 07635370bc
commit a7f7802ceb
5 changed files with 271 additions and 249 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,110 @@
# Tag used to declare a javadoc namespace to shorten javadoc references.
#
# Usage:
# {% jdoc_nspace :coreast core::lang.ast %}
# {% jdoc_nspace :jast java::lang.java.ast %}
#
# * The first argument is the name of the namespace, it can be prefixed with a ":" for readability
# * The second argument is the package prefix of the namespace, which itself must use an already declared namespace
# Base namespaces are declared for most of the modules of PMD, with the "net.sourceforge.pmd" package prefix.
# E.g. "core::" and "pmd-core::" (aliased) point to pmd-core's "net.sourceforge.pmd" package.
#
# After those tags have been declared, the handle is used with the "name::" syntax, eg {% jdoc jast::ASTType %}
# To refer to only the package prefix defined by the namespace, use instead the ":name" syntax, e.g. {% jdoc_package :jast %}
#
class JDocNamespaceDeclaration < Liquid::Tag
# a namespace is a pair [artifactId, base package]
def initialize(tag_name, arg, tokens)
super
all_args = arg.split(" ")
if all_args.size != 2
"Invalid arguments for jdoc namespace declaration, expected ':name baseNSpace::package.prefix'"
end
@nspace_name = all_args.first.delete(":")
if RESERVED_NSPACES.include?(@nspace_name)
fail "Javadoc namespace #{@nspace_name} is reserved and cannot be redefined"
end
@this_fqcn_unresolved = all_args.last
end
def render(var_ctx)
unless var_ctx[JDOC_NAMESPACE_MAP]
var_ctx[JDOC_NAMESPACE_MAP] = JDocNamespaceDeclaration::make_base_namespaces #base namespace map
end
# Add the resolved QName to the map
var_ctx[JDOC_NAMESPACE_MAP][@nspace_name] = JDocNamespaceDeclaration::parse_fqcn(@this_fqcn_unresolved, var_ctx)
""
end
# Regex to match a prefixed fqcn, used for method arguments
NAMESPACED_FQCN_REGEX = /(\w[\w-]*)::((?:\w+\.)*\w+)/
SYM_REGEX = /:(\w[\w-]*)/
# Parses a namespaced fqcn of the form nspace::a.b.c.Class into a tuple [artifactId, expandedFQCN]
# If allow_sym is true, then the syntax :nspace is allowed as well
def self.parse_fqcn(fqcn, var_ctx, allow_sym = true)
nspace = nil
fqcn_suffix = ""
if NAMESPACED_FQCN_REGEX =~ fqcn
nspace = $1
fqcn_suffix = $2
elsif allow_sym && SYM_REGEX =~ fqcn
nspace = $1
fqcn_suffix = ""
else
fail "Invalid javadoc fqcn format, expected nspace::a.b.c.Class" + (allow_sym ? " or :nspace" : "") + ", but was " + fqcn
end
resolved_nspace = []
unless var_ctx[JDOC_NAMESPACE_MAP] && (resolved_nspace = var_ctx[JDOC_NAMESPACE_MAP][nspace])
fail "Undeclared javadoc namespace #{nspace}"
end
unless resolved_nspace.size == 2
fail "Badly registered namespace (implementation bug)" # just to be safe
end
expanded_fqcn = resolved_nspace.last
unless fqcn_suffix.empty?
expanded_fqcn += "." + fqcn_suffix
end
# Return the resolved artifactId + the expanded FQCN
[resolved_nspace.first, expanded_fqcn]
end
private
JDOC_NAMESPACE_MAP = "jdoc_nspaces"
RESERVED_NSPACES = ['core', 'java', 'apex', 'dist', 'doc', 'xml', 'visualforce', 'ui', 'test'].flat_map {|m| [m, "pmd-" + m]}
def self.make_base_namespaces
res = {}
RESERVED_NSPACES.each do |mod|
pmd_prefixed = mod.start_with?("pmd") ? mod : ("pmd-" + mod)
# Each is aliased, eg core:: is equivalent to pmd-core::
res[mod] = [pmd_prefixed, "net.sourceforge.pmd"]
res[pmd_prefixed] = [pmd_prefixed, "net.sourceforge.pmd"]
end
res
end
end

View File

@ -8,7 +8,7 @@ permalink: pmd_userdocs_extending_defining_properties.html
author: Hooper Bloob <hooperbloob@users.sourceforge.net>, Romain Pelisse <rpelisse@users.sourceforge.net>, Clément Fournier <clement.fournier76@gmail.com> author: Hooper Bloob <hooperbloob@users.sourceforge.net>, Romain Pelisse <rpelisse@users.sourceforge.net>, Clément Fournier <clement.fournier76@gmail.com>
--- ---
{% jdoc_context core @.properties %} {% jdoc_nspace :props core::properties %}
## Defining properties ## Defining properties
@ -53,9 +53,9 @@ Note that RegexProperty doesn't have a multivalued variant, since the delimiters
The procedure to define a property is quite straightforward: The procedure to define a property is quite straightforward:
* Create a property descriptor of the type you want, using its builder; * Create a property descriptor of the type you want, using its builder;
* Call {% jdoc !args!@.PropertySource#definePropertyDescriptor(@.PropertyDescriptor) %}` in the rule's noarg constructor. * Call {% jdoc !a!props::PropertySource#definePropertyDescriptor(props::PropertyDescriptor) %}` in the rule's noarg constructor.
You can then retrieve the value of the property at any time using {% jdoc !args!@.PropertySource#getProperty(@.PropertyDescriptor) %}. You can then retrieve the value of the property at any time using {% jdoc !a!props::PropertySource#getProperty(props::PropertyDescriptor) %}.
#### Creating a descriptor #### Creating a descriptor
@ -173,4 +173,3 @@ Multivalued properties are also allowed and their `type` attribute has the form
Notice that in the example above, `@Image = $reportedIdentifiers` doesn't test `@Image` for equality with the whole sequence `('foo', 'bar')`, it tests whether the sequence *contains* `@Image`. That is, the above rule will report all variables named `foo` or `bar`. All other XPath 2.0 [functions operating on sequences](https://www.w3.org/TR/xpath-functions/#sequence-functions) are supported. Notice that in the example above, `@Image = $reportedIdentifiers` doesn't test `@Image` for equality with the whole sequence `('foo', 'bar')`, it tests whether the sequence *contains* `@Image`. That is, the above rule will report all variables named `foo` or `bar`. All other XPath 2.0 [functions operating on sequences](https://www.w3.org/TR/xpath-functions/#sequence-functions) are supported.
{% endjdoc_context %}

View File

@ -9,10 +9,10 @@ permalink: pmd_userdocs_extending_metrics_howto.html
author: Clément Fournier <clement.fournier76@gmail.com> author: Clément Fournier <clement.fournier76@gmail.com>
--- ---
{% jdoc_handle @{coremx} core @.lang.metrics %} {% jdoc_nspace :coremx core::lang.metrics %}
{% jdoc_handle @{coreast} core @.lang.ast %} {% jdoc_nspace :coreast core::lang.ast %}
{% jdoc_handle @{jmx} java @.lang.java.metrics %} {% jdoc_nspace :jmx java::lang.java.metrics %}
{% jdoc_handle @{jast} java @.lang.java.ast %} {% jdoc_nspace :jast java::lang.java.ast %}
## Using the metrics framework ## Using the metrics framework
@ -25,8 +25,8 @@ a numeric result. In the Java framework, metrics can be computed on operation de
method declaration), and type declaration nodes (class, interface, enum, and annotation declarations). A metric method declaration), and type declaration nodes (class, interface, enum, and annotation declarations). A metric
object in the framework can only handle either types or operations, but not both. object in the framework can only handle either types or operations, but not both.
PMD ships with a library of already implemented metrics. These metrics are referenced by {% jdoc @{coremx}.MetricKey %} objects, PMD ships with a library of already implemented metrics. These metrics are referenced by {% jdoc coremx::MetricKey %} objects,
which are listed in two public enums: {% jdoc @{jmx}.api.JavaClassMetricKey %} and {% jdoc @{jmx}.api.JavaOperationMetricKey %}. which are listed in two public enums: {% jdoc jmx::api.JavaClassMetricKey %} and {% jdoc jmx::api.JavaOperationMetricKey %}.
Metric keys wrap a metric, and know which type of node their metric can be computed on. That way, you cannot compute an operation metric on a class Metric keys wrap a metric, and know which type of node their metric can be computed on. That way, you cannot compute an operation metric on a class
declaration node. Metrics that can be computed on both operation and type declarations (e.g. NCSS) have one metric key in declaration node. Metrics that can be computed on both operation and type declarations (e.g. NCSS) have one metric key in
each enum. each enum.
@ -38,7 +38,7 @@ which is the name of the metric key as defined in `JavaClassMetricKey` or `Java
will be **computed on the context node**. will be **computed on the context node**.
The function will throw an exception in the following cases: The function will throw an exception in the following cases:
* The context node is neither an instance of {% jdoc @{jast}.ASTAnyTypeDeclaration %} or {% jdoc @{jast}.MethodLikeNode %}, that is, * The context node is neither an instance of {% jdoc jast::ASTAnyTypeDeclaration %} or {% jdoc jast::MethodLikeNode %}, that is,
it's not one of `ClassOrInterfaceDeclaration`, `EnumDeclaration`, `AnnotationDeclaration`, `MethodDeclaration`, it's not one of `ClassOrInterfaceDeclaration`, `EnumDeclaration`, `AnnotationDeclaration`, `MethodDeclaration`,
`ConstructorDeclaration`, or `LambdaExpression`. `ConstructorDeclaration`, or `LambdaExpression`.
* The metric key does not exist (the name is case insensitive) or is not defined for the type of the context node. * The metric key does not exist (the name is case insensitive) or is not defined for the type of the context node.
@ -56,7 +56,7 @@ it's not one of `ClassOrInterfaceDeclaration`, `EnumDeclaration`, `AnnotationDec
## For Java Rules ## For Java Rules
The static façade class {% jdoc @{jmx}.JavaMetrics %} is the single entry point to compute metrics in the Java framework. The static façade class {% jdoc jmx::JavaMetrics %} is the single entry point to compute metrics in the Java framework.
This class provides the method `get` and its overloads. The following sections describes the interface of this class. This class provides the method `get` and its overloads. The following sections describes the interface of this class.
@ -86,7 +86,7 @@ to `JavaMetrics.get`.
### Capability checking ### Capability checking
Metrics are not necessarily computable on any node of the type they handle. For example, Cyclo cannot be computed on Metrics are not necessarily computable on any node of the type they handle. For example, Cyclo cannot be computed on
abstract methods. Metric keys provides a {% jdoc !args!@{coremx}.MetricKey#supports(@{coreast}.Node) %} boolean method abstract methods. Metric keys provides a {% jdoc !a!coremx::MetricKey#supports(coreast::Node) %} boolean method
to find out if the metric can be computed on to find out if the metric can be computed on
the specified node. **If the metric cannot be computed on the given node, `JavaMetrics.get` will return `Double.NaN` .** the specified node. **If the metric cannot be computed on the given node, `JavaMetrics.get` will return `Double.NaN` .**
If you're concerned about that, you can condition your call on whether the node is supported or not: If you're concerned about that, you can condition your call on whether the node is supported or not:
@ -108,7 +108,7 @@ Some metrics define options that can be used to slightly modify the computation.
gathered inside an enum in the implementation class of the metric, for example `CycloMetric.CycloOption`. They're gathered inside an enum in the implementation class of the metric, for example `CycloMetric.CycloOption`. They're
also documented on the [index of metrics](pmd_java_metrics_index.html). also documented on the [index of metrics](pmd_java_metrics_index.html).
To use options with a metric, you must first bundle them into a {% jdoc @.<<.<<.metrics.MetricOptions %} object. `MetricOptions` provides the To use options with a metric, you must first bundle them into a {% jdoc coremx::MetricOptions %} object. `MetricOptions` provides the
utility method `ofOptions` to get a `MetricOptions` bundle from a collection or with varargs parameters. You can then utility method `ofOptions` to get a `MetricOptions` bundle from a collection or with varargs parameters. You can then
pass this bundle as a parameter to `JavaMetrics.get`: pass this bundle as a parameter to `JavaMetrics.get`:
```java ```java

View File

@ -33,12 +33,13 @@ This is a {{ site.pmd.release_type }} release.
### API Changes ### API Changes
{% jdoc_context "core @.lang.ast.xpath" %} {% jdoc_nspace :xpath core::lang.ast.xpath %}
* The implementation of the adapters for the XPath engines Saxon and Jaxen (package {% jdoc_package @ %}) * The implementation of the adapters for the XPath engines Saxon and Jaxen (package {% jdoc_package :xpath %})
are now deprecated. They'll be moved to an internal package come 7.0.0. Only {% jdoc @.Attribute %} remains public API. are now deprecated. They'll be moved to an internal package come 7.0.0. Only {% jdoc xpath::Attribute %} remains public API.
{% jdoc !aq!core::lang.rule.stat.StatisticalRule#SIGMA_DESCRIPTOR %}
{% endjdoc_context %}
### External Contributions ### External Contributions