1010import com .jcabi .xml .XMLDocument ;
1111import com .jcabi .xml .XSL ;
1212import com .jcabi .xml .XSLDocument ;
13- import java .util .ArrayList ;
1413import java .util .Collection ;
15- import java .util .HashSet ;
1614import java .util .List ;
1715import java .util .Map ;
1816import java .util .Objects ;
17+ import java .util .Set ;
18+ import java .util .concurrent .ConcurrentHashMap ;
1919import java .util .function .Function ;
2020import java .util .stream .Collectors ;
2121import java .util .stream .IntStream ;
22+ import java .util .stream .Stream ;
2223import org .cactoos .io .ResourceOf ;
2324import org .cactoos .io .UncheckedInput ;
2425import org .cactoos .list .ListOf ;
2526import org .cactoos .text .TextOf ;
2627import org .cactoos .text .UncheckedText ;
27- import org .eolang .parser .OnDefault ;
2828
2929/**
3030 * All atom FQNs in the entire scope of EO program must be unique.
@@ -69,47 +69,14 @@ public String name() {
6969
7070 @ Override
7171 public Collection <Defect > defects (final Map <String , XML > pkg ) {
72- final Collection <Defect > defects = new ArrayList <>(0 );
7372 final Map <Xnav , List <String >> index = pkg .values ().stream ()
7473 .map (this .pre ::transform )
7574 .map (xmir -> new Xnav (xmir .inner ()))
7675 .collect (Collectors .toMap (Function .identity (), LtAtomIsNotUnique ::fqns ));
77- final Collection <String > checked = new HashSet <>(0 );
78- index .forEach (
79- (xmir , fqns ) -> {
80- fqns .stream ()
81- .collect (Collectors .groupingBy (Function .identity (), Collectors .counting ()))
82- .entrySet ()
83- .stream ()
84- .filter (entry -> entry .getValue () > 1L )
85- .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue ))
86- .forEach (
87- (aname , count ) ->
88- IntStream .range (0 , Math .toIntExact (count )).forEach (
89- pos -> defects .add (this .singleDefect (xmir , aname , pos ))
90- )
91- );
92- index .forEach (
93- (next , names ) -> {
94- if (!Objects .equals (next , xmir )) {
95- final String pair = LtAtomIsNotUnique .pairHash (xmir , next );
96- if (!checked .contains (pair )) {
97- checked .add (pair );
98- names .stream ()
99- .filter (fqns ::contains )
100- .forEach (
101- aname -> {
102- defects .add (this .sharedDefect (next , xmir , aname ));
103- defects .add (this .sharedDefect (xmir , next , aname ));
104- }
105- );
106- }
107- }
108- }
109- );
110- }
111- );
112- return defects ;
76+ return Stream .concat (
77+ this .duplicateDefects (index ),
78+ this .sharedDefects (index )
79+ ).collect (Collectors .toList ());
11380 }
11481
11582 @ Override
@@ -125,11 +92,60 @@ public String motive() {
12592 ).asString ();
12693 }
12794
95+ /**
96+ * Find duplicate defects within single source.
97+ * @param index Index of FQNs by source
98+ * @return Stream of defects
99+ */
100+ private Stream <Defect > duplicateDefects (final Map <Xnav , List <String >> index ) {
101+ return index .entrySet ().stream ()
102+ .flatMap (
103+ entry -> entry .getValue ().stream ()
104+ .collect (Collectors .groupingBy (Function .identity (), Collectors .counting ()))
105+ .entrySet ()
106+ .stream ()
107+ .filter (e -> e .getValue () > 1L )
108+ .flatMap (
109+ e -> IntStream .range (0 , Math .toIntExact (e .getValue ()))
110+ .mapToObj (pos -> this .singleDefect (entry .getKey (), e .getKey (), pos ))
111+ )
112+ );
113+ }
114+
115+ /**
116+ * Find shared defects between sources.
117+ * @param index Index of FQNs by source
118+ * @return Stream of defects
119+ */
120+ private Stream <Defect > sharedDefects (final Map <Xnav , List <String >> index ) {
121+ final Set <String > checked = ConcurrentHashMap .newKeySet ();
122+ return index .entrySet ().stream ()
123+ .flatMap (
124+ entry -> index .entrySet ().stream ()
125+ .filter (other -> !Objects .equals (other .getKey (), entry .getKey ()))
126+ .filter (
127+ other -> checked .add (
128+ LtAtomIsNotUnique .pairHash (entry .getKey (), other .getKey ())
129+ )
130+ )
131+ .flatMap (
132+ other -> other .getValue ().stream ()
133+ .filter (entry .getValue ()::contains )
134+ .flatMap (
135+ aname -> Stream .of (
136+ this .sharedDefect (other .getKey (), entry .getKey (), aname ),
137+ this .sharedDefect (entry .getKey (), other .getKey (), aname )
138+ )
139+ )
140+ )
141+ );
142+ }
143+
128144 private Defect singleDefect (final Xnav xml , final String fqn , final int pos ) {
129145 return new Defect .Default (
130146 this .name (),
131147 Severity .ERROR ,
132- new OnDefault (new XMLDocument (xml .node ())).get (),
148+ new ProgramName (new XMLDocument (xml .node ())).get (),
133149 Integer .parseInt (
134150 xml .path (
135151 String .format ("//o[@name='%s' and o[@name='λ']]" , LtAtomIsNotUnique .oname (fqn ))
@@ -145,7 +161,7 @@ private Defect sharedDefect(final Xnav xml, final Xnav original, final String fq
145161 return new Defect .Default (
146162 this .name (),
147163 Severity .ERROR ,
148- new OnDefault (new XMLDocument (xml .node ())).get (),
164+ new ProgramName (new XMLDocument (xml .node ())).get (),
149165 Integer .parseInt (
150166 xml .path (
151167 String .format ("//o[@name='%s' and o[@name='λ']]" , LtAtomIsNotUnique .oname (fqn ))
@@ -156,7 +172,7 @@ private Defect sharedDefect(final Xnav xml, final Xnav original, final String fq
156172 String .format (
157173 "Atom with FQN \" %s\" is duplicated, original was found in \" %s\" " ,
158174 fqn ,
159- new OnDefault (new XMLDocument (original .node ())).get ()
175+ new ProgramName (new XMLDocument (original .node ())).get ()
160176 )
161177 );
162178 }
0 commit comments